diff --git a/docs/admin/repo-admin.rst b/docs/admin/repo-admin.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo-admin.rst @@ -0,0 +1,28 @@ +.. _repo-admin-set: +.. _permissions-info-add-group-ref: + +Repository Administration +========================= + +Repository permissions in |RCE| can be managed in a number of different ways. +This overview should give you an insight into how you could adopt particular +settings for your needs: + +* Global |repo| permissions: This allows you to set the default permissions + for each new |repo| created within |RCE|, see :ref:`repo-default-ref`. All + |repos| created will inherit these permissions unless explicitly configured. +* Individual |repo| permissions: To set individual |repo| permissions, + see :ref:`set-repo-perms`. +* Repository Group permissions: This allows you to define the permissions for + a group, and all |repos| created within that group will inherit the same + permissions. + +.. toctree:: + + repo_admin/repo-perm-steps + repo_admin/repo-extra-fields + repo_admin/repo-hooks + repo_admin/repo-issue-tracker + repo_admin/repo-vcs + repo_admin/restore-deleted-repositories + repo_admin/repo-admin-tasks \ No newline at end of file diff --git a/docs/admin/repo_admin/repo-admin-tasks.rst b/docs/admin/repo_admin/repo-admin-tasks.rst new file mode 100644 --- /dev/null +++ b/docs/admin/repo_admin/repo-admin-tasks.rst @@ -0,0 +1,24 @@ +.. _repo-admin-tasks: + +Common Admin Tasks for Repositories +----------------------------------- + + +Manually Force Delete Repository +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In case of attached forks or pull-requests repositories should be archived. +Here is how to force delete a repository and remove all dependent objects + + +.. code-block:: bash + + # starts the ishell interactive prompt + $ rccontrol ishell enterprise-1 + +.. code-block:: python + + In [4]: from rhodecode.model.repo import RepoModel + In [3]: repo = Repository.get_by_repo_name('test_repos/repo_with_prs') + In [5]: RepoModel().delete(repo, forks='detach', pull_requests='delete') + In [6]: Session().commit() diff --git a/docs/admin/repo-extra-fields.rst b/docs/admin/repo_admin/repo-extra-fields.rst rename from docs/admin/repo-extra-fields.rst rename to docs/admin/repo_admin/repo-extra-fields.rst --- a/docs/admin/repo-extra-fields.rst +++ b/docs/admin/repo_admin/repo-extra-fields.rst @@ -29,7 +29,7 @@ 1. Go to :menuselection:`Admin --> Repos beside the |repo| to which you wish to add extra fields. 2. On the |repo| settings page, select the :guilabel:`Extra fields` tab. -.. image:: ../images/extra-repo-fields.png +.. image:: ../../images/extra-repo-fields.png The most important is the `New field key` variable which under the value will be stored. It needs to be unique for each repository. The label and description diff --git a/docs/admin/repo-hooks.rst b/docs/admin/repo_admin/repo-hooks.rst rename from docs/admin/repo-hooks.rst rename to docs/admin/repo_admin/repo-hooks.rst diff --git a/docs/admin/repo-issue-tracker.rst b/docs/admin/repo_admin/repo-issue-tracker.rst rename from docs/admin/repo-issue-tracker.rst rename to docs/admin/repo_admin/repo-issue-tracker.rst diff --git a/docs/admin/repo-perm-steps.rst b/docs/admin/repo_admin/repo-perm-steps.rst rename from docs/admin/repo-perm-steps.rst rename to docs/admin/repo_admin/repo-perm-steps.rst diff --git a/docs/admin/repo-vcs.rst b/docs/admin/repo_admin/repo-vcs.rst rename from docs/admin/repo-vcs.rst rename to docs/admin/repo_admin/repo-vcs.rst diff --git a/docs/admin/restore-deleted-repositories.rst b/docs/admin/repo_admin/restore-deleted-repositories.rst rename from docs/admin/restore-deleted-repositories.rst rename to docs/admin/repo_admin/restore-deleted-repositories.rst diff --git a/docs/admin/setting-repo-perms.rst b/docs/admin/setting-repo-perms.rst deleted file mode 100644 --- a/docs/admin/setting-repo-perms.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _permissions-info-add-group-ref: - -Repository Administration -========================= - -Repository permissions in |RCE| can be managed in a number of different ways. -This overview should give you an insight into how you could adopt particular -settings for your needs: - -* Global |repo| permissions: This allows you to set the default permissions - for each new |repo| created within |RCE|, see :ref:`repo-default-ref`. All - |repos| created will inherit these permissions unless explicitly configured. -* Individual |repo| permissions: To set individual |repo| permissions, - see :ref:`set-repo-perms`. -* Repository Group permissions: This allows you to define the permissions for - a group, and all |repos| created within that group will inherit the same - permissions. - -.. toctree:: - - repo-perm-steps - repo-extra-fields - repo-hooks - repo-issue-tracker - repo-vcs - diff --git a/docs/admin/system-admin.rst b/docs/admin/system-admin.rst --- a/docs/admin/system-admin.rst +++ b/docs/admin/system-admin.rst @@ -16,19 +16,17 @@ The following are the most common system .. toctree:: - config-files-overview - vcs-server - svn-http - svn-path-permissions - gunicorn-ssl-support - apache-config - nginx-config - backup-restore - tuning-rhodecode - indexing - reset-information - enable-debug - admin-tricks - cleanup-cmds - restore-deleted-repositories - + system_admin/config-files-overview + system_admin/vcs-server + system_admin/svn-http + system_admin/svn-path-permissions + system_admin/gunicorn-ssl-support + system_admin/apache-config + system_admin/nginx-config + system_admin/backup-restore + system_admin/tuning-rhodecode + system_admin/indexing + system_admin/reset-information + system_admin/enable-debug + system_admin/admin-tricks + system_admin/cleanup-cmds diff --git a/docs/admin/admin-tricks.rst b/docs/admin/system_admin/admin-tricks.rst rename from docs/admin/admin-tricks.rst rename to docs/admin/system_admin/admin-tricks.rst --- a/docs/admin/admin-tricks.rst +++ b/docs/admin/system_admin/admin-tricks.rst @@ -57,7 +57,7 @@ 2. To add a message that will be display 3. Select :guilabel:`Save`, and you will see the message once your page refreshes. -.. image:: ../images/server-wide-announcement.png +.. image:: ../../images/server-wide-announcement.png :alt: Server Wide Announcement .. _md-rst: @@ -207,7 +207,7 @@ 2. Restart the |RCE| instance and check Instance "enterprise-2" successfully stopped. Instance "enterprise-2" successfully started. -.. image:: ../images/language.png +.. image:: ../../images/language.png .. _set-repo-pub: diff --git a/docs/admin/apache-config.rst b/docs/admin/system_admin/apache-config.rst rename from docs/admin/apache-config.rst rename to docs/admin/system_admin/apache-config.rst --- a/docs/admin/apache-config.rst +++ b/docs/admin/system_admin/apache-config.rst @@ -8,7 +8,7 @@ the information in the following section .. toctree:: - apache-conf-example - apache-diffie-hellman - apache-subdirectory - apache-wsgi-coding + apache/apache-conf-example + apache/apache-diffie-hellman + apache/apache-subdirectory + apache/apache-wsgi-coding diff --git a/docs/admin/apache-conf-example.rst b/docs/admin/system_admin/apache/apache-conf-example.rst rename from docs/admin/apache-conf-example.rst rename to docs/admin/system_admin/apache/apache-conf-example.rst diff --git a/docs/admin/apache-diffie-hellman.rst b/docs/admin/system_admin/apache/apache-diffie-hellman.rst rename from docs/admin/apache-diffie-hellman.rst rename to docs/admin/system_admin/apache/apache-diffie-hellman.rst diff --git a/docs/admin/apache-subdirectory.rst b/docs/admin/system_admin/apache/apache-subdirectory.rst rename from docs/admin/apache-subdirectory.rst rename to docs/admin/system_admin/apache/apache-subdirectory.rst diff --git a/docs/admin/apache-wsgi-coding.rst b/docs/admin/system_admin/apache/apache-wsgi-coding.rst rename from docs/admin/apache-wsgi-coding.rst rename to docs/admin/system_admin/apache/apache-wsgi-coding.rst diff --git a/docs/admin/backup-restore.rst b/docs/admin/system_admin/backup-restore.rst rename from docs/admin/backup-restore.rst rename to docs/admin/system_admin/backup-restore.rst diff --git a/docs/admin/cleanup-cmds.rst b/docs/admin/system_admin/cleanup-cmds.rst rename from docs/admin/cleanup-cmds.rst rename to docs/admin/system_admin/cleanup-cmds.rst diff --git a/docs/admin/config-files-overview.rst b/docs/admin/system_admin/config-files-overview.rst rename from docs/admin/config-files-overview.rst rename to docs/admin/system_admin/config-files-overview.rst diff --git a/docs/admin/enable-debug.rst b/docs/admin/system_admin/enable-debug.rst rename from docs/admin/enable-debug.rst rename to docs/admin/system_admin/enable-debug.rst diff --git a/docs/admin/gunicorn-ssl-support.rst b/docs/admin/system_admin/gunicorn-ssl-support.rst rename from docs/admin/gunicorn-ssl-support.rst rename to docs/admin/system_admin/gunicorn-ssl-support.rst diff --git a/docs/admin/indexing.rst b/docs/admin/system_admin/indexing.rst rename from docs/admin/indexing.rst rename to docs/admin/system_admin/indexing.rst diff --git a/docs/admin/nginx-config.rst b/docs/admin/system_admin/nginx-config.rst rename from docs/admin/nginx-config.rst rename to docs/admin/system_admin/nginx-config.rst --- a/docs/admin/nginx-config.rst +++ b/docs/admin/system_admin/nginx-config.rst @@ -8,7 +8,7 @@ the information in the following section .. toctree:: - nginx-config-example - nginx-diffie-hellman - nginx-proxy-conf - nginx-url-prefix + nginx/nginx-config-example + nginx/nginx-diffie-hellman + nginx/nginx-proxy-conf + nginx/nginx-url-prefix diff --git a/docs/admin/nginx-config-example.rst b/docs/admin/system_admin/nginx/nginx-config-example.rst rename from docs/admin/nginx-config-example.rst rename to docs/admin/system_admin/nginx/nginx-config-example.rst diff --git a/docs/admin/nginx-diffie-hellman.rst b/docs/admin/system_admin/nginx/nginx-diffie-hellman.rst rename from docs/admin/nginx-diffie-hellman.rst rename to docs/admin/system_admin/nginx/nginx-diffie-hellman.rst diff --git a/docs/admin/nginx-proxy-conf.rst b/docs/admin/system_admin/nginx/nginx-proxy-conf.rst rename from docs/admin/nginx-proxy-conf.rst rename to docs/admin/system_admin/nginx/nginx-proxy-conf.rst diff --git a/docs/admin/nginx-url-prefix.rst b/docs/admin/system_admin/nginx/nginx-url-prefix.rst rename from docs/admin/nginx-url-prefix.rst rename to docs/admin/system_admin/nginx/nginx-url-prefix.rst diff --git a/docs/admin/reset-information.rst b/docs/admin/system_admin/reset-information.rst rename from docs/admin/reset-information.rst rename to docs/admin/system_admin/reset-information.rst diff --git a/docs/admin/svn-http.rst b/docs/admin/system_admin/svn-http.rst rename from docs/admin/svn-http.rst rename to docs/admin/system_admin/svn-http.rst diff --git a/docs/admin/svn-path-permissions.rst b/docs/admin/system_admin/svn-path-permissions.rst rename from docs/admin/svn-path-permissions.rst rename to docs/admin/system_admin/svn-path-permissions.rst diff --git a/docs/admin/tuning-rhodecode.rst b/docs/admin/system_admin/tuning-rhodecode.rst rename from docs/admin/tuning-rhodecode.rst rename to docs/admin/system_admin/tuning-rhodecode.rst --- a/docs/admin/tuning-rhodecode.rst +++ b/docs/admin/system_admin/tuning-rhodecode.rst @@ -8,14 +8,14 @@ may find some of the following methods u .. toctree:: - tuning-gunicorn - tuning-vcs-memory-cache - tuning-user-sessions-performance - tuning-increase-db-performance - tuning-scale-horizontally-cluster - tuning-mount-cache-memory - tuning-change-encoding - tuning-change-large-file-dir - tuning-change-lfs-dir - tuning-hg-auth-loop + tuning/tuning-gunicorn + tuning/tuning-vcs-memory-cache + tuning/tuning-user-sessions-performance + tuning/tuning-increase-db-performance + tuning/tuning-scale-horizontally-cluster + tuning/tuning-mount-cache-memory + tuning/tuning-change-encoding + tuning/tuning-change-large-file-dir + tuning/tuning-change-lfs-dir + tuning/tuning-hg-auth-loop diff --git a/docs/admin/tuning-change-encoding.rst b/docs/admin/system_admin/tuning/tuning-change-encoding.rst rename from docs/admin/tuning-change-encoding.rst rename to docs/admin/system_admin/tuning/tuning-change-encoding.rst diff --git a/docs/admin/tuning-change-large-file-dir.rst b/docs/admin/system_admin/tuning/tuning-change-large-file-dir.rst rename from docs/admin/tuning-change-large-file-dir.rst rename to docs/admin/system_admin/tuning/tuning-change-large-file-dir.rst diff --git a/docs/admin/tuning-change-lfs-dir.rst b/docs/admin/system_admin/tuning/tuning-change-lfs-dir.rst rename from docs/admin/tuning-change-lfs-dir.rst rename to docs/admin/system_admin/tuning/tuning-change-lfs-dir.rst diff --git a/docs/admin/tuning-gunicorn.rst b/docs/admin/system_admin/tuning/tuning-gunicorn.rst rename from docs/admin/tuning-gunicorn.rst rename to docs/admin/system_admin/tuning/tuning-gunicorn.rst --- a/docs/admin/tuning-gunicorn.rst +++ b/docs/admin/system_admin/tuning/tuning-gunicorn.rst @@ -42,7 +42,7 @@ 2. In the ``[server:main]`` section, cha ## restarted, could prevent memory leaks max_requests = 1000 max_requests_jitter = 30 - ## amount of time a worker can spend with handling a request before it + ## amount of time a worker can spend with handling a request tuning-change-lfs-dir.before it ## gets killed and restarted. Set to 6hrs timeout = 21600 diff --git a/docs/admin/tuning-hg-auth-loop.rst b/docs/admin/system_admin/tuning/tuning-hg-auth-loop.rst rename from docs/admin/tuning-hg-auth-loop.rst rename to docs/admin/system_admin/tuning/tuning-hg-auth-loop.rst diff --git a/docs/admin/tuning-increase-db-performance.rst b/docs/admin/system_admin/tuning/tuning-increase-db-performance.rst rename from docs/admin/tuning-increase-db-performance.rst rename to docs/admin/system_admin/tuning/tuning-increase-db-performance.rst diff --git a/docs/admin/tuning-mount-cache-memory.rst b/docs/admin/system_admin/tuning/tuning-mount-cache-memory.rst rename from docs/admin/tuning-mount-cache-memory.rst rename to docs/admin/system_admin/tuning/tuning-mount-cache-memory.rst diff --git a/docs/admin/tuning-scale-horizontally-cluster.rst b/docs/admin/system_admin/tuning/tuning-scale-horizontally-cluster.rst rename from docs/admin/tuning-scale-horizontally-cluster.rst rename to docs/admin/system_admin/tuning/tuning-scale-horizontally-cluster.rst diff --git a/docs/admin/tuning-user-sessions-performance.rst b/docs/admin/system_admin/tuning/tuning-user-sessions-performance.rst rename from docs/admin/tuning-user-sessions-performance.rst rename to docs/admin/system_admin/tuning/tuning-user-sessions-performance.rst diff --git a/docs/admin/tuning-vcs-memory-cache.rst b/docs/admin/system_admin/tuning/tuning-vcs-memory-cache.rst rename from docs/admin/tuning-vcs-memory-cache.rst rename to docs/admin/system_admin/tuning/tuning-vcs-memory-cache.rst diff --git a/docs/admin/vcs-server.rst b/docs/admin/system_admin/vcs-server.rst rename from docs/admin/vcs-server.rst rename to docs/admin/system_admin/vcs-server.rst diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -204,6 +204,7 @@ are not required in args. methods/pull-request-methods methods/repo-methods methods/repo-group-methods + methods/search-methods methods/server-methods methods/user-methods methods/user-group-methods diff --git a/docs/api/methods/repo-methods.rst b/docs/api/methods/repo-methods.rst --- a/docs/api/methods/repo-methods.rst +++ b/docs/api/methods/repo-methods.rst @@ -462,6 +462,7 @@ get_repo_file :param cache: Use internal caches for fetching files. If disabled fetching files is slower but more memory efficient :type cache: Optional(bool) + Example output: .. code-block:: bash @@ -499,53 +500,51 @@ get_repo_nodes .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=, details=, max_file_bytes=) Returns a list of nodes and children in a flat list for a given - path at given revision. + path at given revision. - It's possible to specify ret_type to show only `files` or `dirs`. + It's possible to specify ret_type to show only `files` or `dirs`. - This command can only be run using an |authtoken| with admin rights, - or users with at least read rights to |repos|. + This command can only be run using an |authtoken| with admin rights, + or users with at least read rights to |repos|. - :param apiuser: This is filled automatically from the |authtoken|. - :type apiuser: AuthUser - :param repoid: The repository name or repository ID. - :type repoid: str or int - :param revision: The revision for which listing should be done. - :type revision: str - :param root_path: The path from which to start displaying. - :type root_path: str - :param ret_type: Set the return type. Valid options are - ``all`` (default), ``files`` and ``dirs``. - :type ret_type: Optional(str) - :param details: Returns extended information about nodes, such as - md5, binary, and or content. - The valid options are ``basic`` and ``full``. - :type details: Optional(str) - :param max_file_bytes: Only return file content under this file size bytes - :type details: Optional(int) - - Example output: + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: The repository name or repository ID. + :type repoid: str or int + :param revision: The revision for which listing should be done. + :type revision: str + :param root_path: The path from which to start displaying. + :type root_path: str + :param ret_type: Set the return type. Valid options are + ``all`` (default), ``files`` and ``dirs``. + :type ret_type: Optional(str) + :param details: Returns extended information about nodes, such as + md5, binary, and or content. + The valid options are ``basic`` and ``full``. + :type details: Optional(str) + :param max_file_bytes: Only return file content under this file size bytes + :type details: Optional(int) - .. code-block:: bash + Example output: + + .. code-block:: bash - id : - result: [ - { - "binary": false, - "content": "File line - Line2 - ", - "extension": "md", - "lines": 2, - "md5": "059fa5d29b19c0657e384749480f6422", - "mimetype": "text/x-minidsrc", - "name": "file.md", - "size": 580, - "type": "file" - }, - ... - ] - error: null + id : + result: [ + { + "binary": false, + "content": "File line", + "extension": "md", + "lines": 2, + "md5": "059fa5d29b19c0657e384749480f6422", + "mimetype": "text/x-minidsrc", + "name": "file.md", + "size": 580, + "type": "file" + }, + ... + ] + error: null get_repo_refs diff --git a/docs/api/methods/search-methods.rst b/docs/api/methods/search-methods.rst new file mode 100644 --- /dev/null +++ b/docs/api/methods/search-methods.rst @@ -0,0 +1,35 @@ +.. _search-methods-ref: + +search methods +============== + +search +------ + +.. py:function:: search(apiuser, search_query, search_type, page_limit=, page=, search_sort=, repo_name=, repo_group_name=) + + Fetch Full Text Search results using API. + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param search_query: Search query. + :type search_query: str + :param search_type: Search type. The following are valid options: + * commit + * content + * path + :type search_type: str + :param page_limit: Page item limit, from 1 to 500. Default 10 items. + :type page_limit: Optional(int) + :param page: Page number. Default first page. + :type page: Optional(int) + :param search_sort: Search sort order. Default newfirst. The following are valid options: + * newfirst + * oldfirst + :type search_sort: Optional(str) + :param repo_name: Filter by one repo. Default is all. + :type repo_name: Optional(str) + :param repo_group_name: Filter by one repo group. Default is all. + :type repo_group_name: Optional(str) + + diff --git a/docs/index.rst b/docs/index.rst --- a/docs/index.rst +++ b/docs/index.rst @@ -46,7 +46,7 @@ and commit files and |repos| while manag nix/default-env admin/system-admin admin/user-admin - admin/setting-repo-perms + admin/repo-admin admin/security-tips auth/auth issue-trackers/issue-trackers diff --git a/grunt_config.json b/grunt_config.json --- a/grunt_config.json +++ b/grunt_config.json @@ -35,6 +35,7 @@ "<%= dirs.js.node_modules %>/moment/min/moment.min.js", "<%= dirs.js.node_modules %>/clipboard/dist/clipboard.min.js", "<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js", + "<%= dirs.js.node_modules %>/dropzone/dist/dropzone.js", "<%= dirs.js.node_modules %>/sticky-sidebar/dist/sticky-sidebar.min.js", "<%= dirs.js.node_modules %>/sticky-sidebar/dist/jquery.sticky-sidebar.min.js", "<%= dirs.js.node_modules %>/waypoints/lib/noframework.waypoints.min.js", diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "clipboard": "^2.0.1", "exports-loader": "^0.6.4", "favico.js": "^0.3.10", + "dropzone": "^5.5.0", "grunt": "^0.4.5", "grunt-cli": "^1.3.1", "grunt-contrib-concat": "^0.5.1", diff --git a/pkgs/node-packages.nix b/pkgs/node-packages.nix --- a/pkgs/node-packages.nix +++ b/pkgs/node-packages.nix @@ -211,13 +211,13 @@ let sha512 = "yiUk09opTEnE1lK+tb501ENb+yQBi4p++Ep0eGJAHesVYKVMPNgPphVKkIizkDaU+n0SE+zXfTsRbYyOMDYXSg=="; }; }; - "@polymer/polymer-3.1.0" = { + "@polymer/polymer-3.2.0" = { name = "_at_polymer_slash_polymer"; packageName = "@polymer/polymer"; - version = "3.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/@polymer/polymer/-/polymer-3.1.0.tgz"; - sha512 = "hwN8IMERsFATz/9dSMxYHL+84J9uBkPuuarxJWlTsppZ4CAYTZKnepBfNrKoyNsafBmA3yXBiiKPPf+fJtza7A=="; + version = "3.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/@polymer/polymer/-/polymer-3.2.0.tgz"; + sha512 = "L6uV1oM6T6xbwbVx6t3biG5T2VSSB03LxnIrUd9M2pr6RkHVPFHJ37pC5MUwBAEhkGFJif7eks7fdMMSGZTeEQ=="; }; }; "@types/clone-0.1.30" = { @@ -229,13 +229,13 @@ let sha1 = "e7365648c1b42136a59c7d5040637b3b5c83b614"; }; }; - "@types/node-6.14.3" = { + "@types/node-6.14.6" = { name = "_at_types_slash_node"; packageName = "@types/node"; - version = "6.14.3"; - src = fetchurl { - url = "https://registry.npmjs.org/@types/node/-/node-6.14.3.tgz"; - sha512 = "V2VrQBCKo4U0rni6tW4AASRDqIO5ZTLDN/Xzrm4mNBr9SGQYZ+7zZJn+hMs89Q8ZCIHzp4aWQPyCpK+rux1YGA=="; + version = "6.14.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@types/node/-/node-6.14.6.tgz"; + sha512 = "rFs9zCFtSHuseiNXxYxFlun8ibu+jtZPgRM+2ILCmeLiGeGLiIGxuOzD+cNyHegI1GD+da3R/cIbs9+xCLp13w=="; }; }; "@types/parse5-2.2.34" = { @@ -409,22 +409,22 @@ let sha512 = "mJ3QKWtCchL1vhU/kZlJnLPuQZnlDOdZsyP0bbLWPGdYsQDnSBvyTLhzwBA3QAMlzEL9V4JHygEmK6/OTEyytA=="; }; }; - "@webcomponents/shadycss-1.9.0" = { + "@webcomponents/shadycss-1.9.1" = { name = "_at_webcomponents_slash_shadycss"; packageName = "@webcomponents/shadycss"; - version = "1.9.0"; - src = fetchurl { - url = "https://registry.npmjs.org/@webcomponents/shadycss/-/shadycss-1.9.0.tgz"; - sha512 = "g8Xa+6RSEME4g/wLJW4YII0eq15rvXp76RxPAuv7hx+Bdoi7GzZJ/EoZOUfyIbqAsQbII1TcWD4/+Xhs5NcM1w=="; - }; - }; - "@webcomponents/webcomponentsjs-2.2.7" = { + version = "1.9.1"; + src = fetchurl { + url = "https://registry.npmjs.org/@webcomponents/shadycss/-/shadycss-1.9.1.tgz"; + sha512 = "IaZOnWOKXHghqk/WfPNDRIgDBi3RsVPY2IFAw6tYiL9UBGvQRy5R6uC+Fk7qTZsReTJ0xh5MTT8yAcb3MUR4mQ=="; + }; + }; + "@webcomponents/webcomponentsjs-2.2.10" = { name = "_at_webcomponents_slash_webcomponentsjs"; packageName = "@webcomponents/webcomponentsjs"; - version = "2.2.7"; - src = fetchurl { - url = "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.2.7.tgz"; - sha512 = "kPPjzV+5kpoWpTniyvBSPcXS33f3j/C6HvNOJ3YecF3pvz3XwVeU4ammbxtVy/osF3z7hr1DYNptIf4oPEvXZA=="; + version = "2.2.10"; + src = fetchurl { + url = "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.2.10.tgz"; + sha512 = "5dzhUhP+h0qMiK0IWb7VNb0OGBoXO3AuI6Qi8t9PoKT50s5L1jv0xnwnLq+cFgPuTB8FLTNP8xIDmyoOsKBy9Q=="; }; }; "@xtuc/ieee754-1.2.0" = { @@ -499,13 +499,13 @@ let sha1 = "82ffb02b29e662ae53bdc20af15947706739c536"; }; }; - "ajv-6.9.2" = { + "ajv-6.10.0" = { name = "ajv"; packageName = "ajv"; - version = "6.9.2"; - src = fetchurl { - url = "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz"; - sha512 = "4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg=="; + version = "6.10.0"; + src = fetchurl { + url = "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz"; + sha512 = "nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg=="; }; }; "ajv-keywords-3.4.0" = { @@ -743,13 +743,13 @@ let sha512 = "p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw=="; }; }; - "assert-1.4.1" = { + "assert-1.5.0" = { name = "assert"; packageName = "assert"; - version = "1.4.1"; - src = fetchurl { - url = "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz"; - sha1 = "99912d591836b5a6f5b345c0f07eefc08fc65d91"; + version = "1.5.0"; + src = fetchurl { + url = "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz"; + sha512 = "EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA=="; }; }; "assert-plus-0.2.0" = { @@ -815,13 +815,13 @@ let sha512 = "H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg=="; }; }; - "async-each-1.0.1" = { + "async-each-1.0.3" = { name = "async-each"; packageName = "async-each"; - version = "1.0.1"; - src = fetchurl { - url = "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz"; - sha1 = "19d386a1d9edc6e7c1c85d388aedbcc56d33602d"; + version = "1.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz"; + sha512 = "z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="; }; }; "asynckit-0.4.0" = { @@ -1436,22 +1436,22 @@ let sha512 = "vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="; }; }; - "binary-extensions-1.13.0" = { + "binary-extensions-1.13.1" = { name = "binary-extensions"; packageName = "binary-extensions"; - version = "1.13.0"; - src = fetchurl { - url = "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz"; - sha512 = "EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw=="; - }; - }; - "bluebird-3.5.3" = { + version = "1.13.1"; + src = fetchurl { + url = "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz"; + sha512 = "Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="; + }; + }; + "bluebird-3.5.4" = { name = "bluebird"; packageName = "bluebird"; - version = "3.5.3"; - src = fetchurl { - url = "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz"; - sha512 = "/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="; + version = "3.5.4"; + src = fetchurl { + url = "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz"; + sha512 = "FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw=="; }; }; "bn.js-4.11.8" = { @@ -1652,13 +1652,13 @@ let sha1 = "9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"; }; }; - "camelcase-5.0.0" = { + "camelcase-5.3.1" = { name = "camelcase"; packageName = "camelcase"; - version = "5.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz"; - sha512 = "faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA=="; + version = "5.3.1"; + src = fetchurl { + url = "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"; + sha512 = "L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="; }; }; "caniuse-api-1.6.1" = { @@ -1670,22 +1670,22 @@ let sha1 = "b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"; }; }; - "caniuse-db-1.0.30000939" = { + "caniuse-db-1.0.30000967" = { name = "caniuse-db"; packageName = "caniuse-db"; - version = "1.0.30000939"; - src = fetchurl { - url = "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000939.tgz"; - sha512 = "nB5tLf3hOs+biXl1lhKjHRgNC0J1I7H52h/t1FP7qxARKKwpB0z+P/JewJLYAlxCBP/q7rxJzQzHHrQMl0viKg=="; - }; - }; - "caniuse-lite-1.0.30000939" = { + version = "1.0.30000967"; + src = fetchurl { + url = "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000967.tgz"; + sha512 = "70gk6cLSD5rItxnZ7WUxyCpM9LAjEb1tVzlENQfXQXZS/IiGnfAC6u32G5cZFlDBKjNPBIta/QSx5CZLZepxRA=="; + }; + }; + "caniuse-lite-1.0.30000967" = { name = "caniuse-lite"; packageName = "caniuse-lite"; - version = "1.0.30000939"; - src = fetchurl { - url = "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz"; - sha512 = "oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg=="; + version = "1.0.30000967"; + src = fetchurl { + url = "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz"; + sha512 = "rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ=="; }; }; "caseless-0.12.0" = { @@ -1733,13 +1733,13 @@ let sha512 = "Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="; }; }; - "chokidar-2.1.2" = { + "chokidar-2.1.5" = { name = "chokidar"; packageName = "chokidar"; - version = "2.1.2"; - src = fetchurl { - url = "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz"; - sha512 = "IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg=="; + version = "2.1.5"; + src = fetchurl { + url = "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz"; + sha512 = "i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A=="; }; }; "chownr-1.1.1" = { @@ -1967,13 +1967,13 @@ let sha512 = "mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg=="; }; }; - "combined-stream-1.0.7" = { + "combined-stream-1.0.8" = { name = "combined-stream"; packageName = "combined-stream"; - version = "1.0.7"; - src = fetchurl { - url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz"; - sha512 = "brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w=="; + version = "1.0.8"; + src = fetchurl { + url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"; + sha512 = "FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="; }; }; "commander-2.14.1" = { @@ -1994,6 +1994,15 @@ let sha512 = "wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="; }; }; + "commander-2.19.0" = { + name = "commander"; + packageName = "commander"; + version = "2.19.0"; + src = fetchurl { + url = "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz"; + sha512 = "6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="; + }; + }; "commondir-1.0.1" = { name = "commondir"; packageName = "commondir"; @@ -2003,13 +2012,13 @@ let sha1 = "ddd800da0c66127393cca5950ea968a3aaf1253b"; }; }; - "component-emitter-1.2.1" = { + "component-emitter-1.3.0" = { name = "component-emitter"; packageName = "component-emitter"; - version = "1.2.1"; - src = fetchurl { - url = "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz"; - sha1 = "137918d6d78283f7df7a6b7c5a63e140e69425e6"; + version = "1.3.0"; + src = fetchurl { + url = "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"; + sha512 = "Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="; }; }; "concat-map-0.0.1" = { @@ -2480,6 +2489,15 @@ let sha1 = "dcd8488a26f563d61079e48c9f7b7e32373682cf"; }; }; + "dropzone-5.5.1" = { + name = "dropzone"; + packageName = "dropzone"; + version = "5.5.1"; + src = fetchurl { + url = "https://registry.npmjs.org/dropzone/-/dropzone-5.5.1.tgz"; + sha512 = "3VduRWLxx9hbVr42QieQN25mx/I61/mRdUSuxAmDGdDqZIN8qtP7tcKMa3KfpJjuGjOJGYYUzzeq6eGDnkzesA=="; + }; + }; "duplexify-3.7.1" = { name = "duplexify"; packageName = "duplexify"; @@ -2498,13 +2516,13 @@ let sha1 = "3a83a904e54353287874c564b7549386849a98c9"; }; }; - "electron-to-chromium-1.3.113" = { + "electron-to-chromium-1.3.133" = { name = "electron-to-chromium"; packageName = "electron-to-chromium"; - version = "1.3.113"; - src = fetchurl { - url = "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz"; - sha512 = "De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g=="; + version = "1.3.133"; + src = fetchurl { + url = "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.133.tgz"; + sha512 = "lyoC8aoqbbDqsprb6aPdt9n3DpOZZzdz/T4IZKsR0/dkZIxnJVUjjcpOSwA66jPRIOyDAamCTAUqweU05kKNSg=="; }; }; "elliptic-6.4.1" = { @@ -2615,13 +2633,13 @@ let sha1 = "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"; }; }; - "eslint-scope-4.0.0" = { + "eslint-scope-4.0.3" = { name = "eslint-scope"; packageName = "eslint-scope"; - version = "4.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz"; - sha512 = "1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA=="; + version = "4.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz"; + sha512 = "p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg=="; }; }; "espree-3.5.4" = { @@ -2912,13 +2930,13 @@ let sha1 = "9326b1488c22d1a6088650a86901b2d9a90a2cbc"; }; }; - "fined-1.1.1" = { + "fined-1.2.0" = { name = "fined"; packageName = "fined"; - version = "1.1.1"; - src = fetchurl { - url = "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz"; - sha512 = "jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g=="; + version = "1.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz"; + sha512 = "ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng=="; }; }; "flagged-respawn-1.0.1" = { @@ -3020,13 +3038,13 @@ let sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f"; }; }; - "fsevents-1.2.7" = { + "fsevents-1.2.9" = { name = "fsevents"; packageName = "fsevents"; - version = "1.2.7"; - src = fetchurl { - url = "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz"; - sha512 = "Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw=="; + version = "1.2.9"; + src = fetchurl { + url = "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz"; + sha512 = "oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw=="; }; }; "function-bind-1.1.1" = { @@ -3110,13 +3128,13 @@ let sha1 = "4a973f635b9190f715d10987d5c00fd2815ebe3d"; }; }; - "glob-7.1.3" = { + "glob-7.1.4" = { name = "glob"; packageName = "glob"; - version = "7.1.3"; - src = fetchurl { - url = "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz"; - sha512 = "vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ=="; + version = "7.1.4"; + src = fetchurl { + url = "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz"; + sha512 = "hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A=="; }; }; "glob-parent-3.1.0" = { @@ -3605,13 +3623,13 @@ let sha1 = "83f0a0ec378bf3246178b6c2ad9136f135b1c962"; }; }; - "ieee754-1.1.12" = { + "ieee754-1.1.13" = { name = "ieee754"; packageName = "ieee754"; - version = "1.1.12"; - src = fetchurl { - url = "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz"; - sha512 = "GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA=="; + version = "1.1.13"; + src = fetchurl { + url = "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz"; + sha512 = "4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="; }; }; "iferr-0.1.5" = { @@ -3929,13 +3947,13 @@ let sha1 = "7ba5ae24217804ac70707b96922567486cc3e84a"; }; }; - "is-glob-4.0.0" = { + "is-glob-4.0.1" = { name = "is-glob"; packageName = "is-glob"; - version = "4.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz"; - sha1 = "9521c76845cc2610a85203ddf080a958c2ffabc0"; + version = "4.0.1"; + src = fetchurl { + url = "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz"; + sha512 = "5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg=="; }; }; "is-number-3.0.0" = { @@ -4163,13 +4181,13 @@ let sha1 = "46c3fec8c1892b12b0833db9bc7622176dbab34b"; }; }; - "jshint-2.10.1" = { + "jshint-2.10.2" = { name = "jshint"; packageName = "jshint"; - version = "2.10.1"; - src = fetchurl { - url = "https://registry.npmjs.org/jshint/-/jshint-2.10.1.tgz"; - sha512 = "9GpPfKeffYBl7oBDX2lHPG16j0AM7D2bn3aLy9DaWTr6CWa0i/7UGhX8WLZ7V14QQnnr4hXbjauTLYg06F+HYw=="; + version = "2.10.2"; + src = fetchurl { + url = "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz"; + sha512 = "e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA=="; }; }; "jshint-2.9.7" = { @@ -4568,13 +4586,13 @@ let sha512 = "xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg=="; }; }; - "mem-4.1.0" = { + "mem-4.3.0" = { name = "mem"; packageName = "mem"; - version = "4.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz"; - sha512 = "I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg=="; + version = "4.3.0"; + src = fetchurl { + url = "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz"; + sha512 = "qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w=="; }; }; "memory-fs-0.4.1" = { @@ -4613,31 +4631,31 @@ let sha512 = "x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="; }; }; - "mime-db-1.38.0" = { + "mime-db-1.40.0" = { name = "mime-db"; packageName = "mime-db"; - version = "1.38.0"; - src = fetchurl { - url = "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz"; - sha512 = "bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg=="; - }; - }; - "mime-types-2.1.22" = { + version = "1.40.0"; + src = fetchurl { + url = "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz"; + sha512 = "jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="; + }; + }; + "mime-types-2.1.24" = { name = "mime-types"; packageName = "mime-types"; - version = "2.1.22"; - src = fetchurl { - url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz"; - sha512 = "aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog=="; - }; - }; - "mimic-fn-1.2.0" = { + version = "2.1.24"; + src = fetchurl { + url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz"; + sha512 = "WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ=="; + }; + }; + "mimic-fn-2.1.0" = { name = "mimic-fn"; packageName = "mimic-fn"; - version = "1.2.0"; - src = fetchurl { - url = "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz"; - sha512 = "jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="; + version = "2.1.0"; + src = fetchurl { + url = "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"; + sha512 = "OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="; }; }; "minimalistic-assert-1.0.1" = { @@ -4739,13 +4757,13 @@ let sha512 = "bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="; }; }; - "mousetrap-1.6.2" = { + "mousetrap-1.6.3" = { name = "mousetrap"; packageName = "mousetrap"; - version = "1.6.2"; - src = fetchurl { - url = "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.2.tgz"; - sha512 = "jDjhi7wlHwdO6q6DS7YRmSHcuI+RVxadBkLt3KHrhd3C2b+w5pKefg3oj5beTcHZyVFA9Aksf+yEE1y5jxUjVA=="; + version = "1.6.3"; + src = fetchurl { + url = "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.3.tgz"; + sha512 = "bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA=="; }; }; "move-concurrently-1.0.1" = { @@ -4766,13 +4784,13 @@ let sha1 = "5608aeadfc00be6c2901df5f9861788de0d597c8"; }; }; - "nan-2.12.1" = { + "nan-2.13.2" = { name = "nan"; packageName = "nan"; - version = "2.12.1"; - src = fetchurl { - url = "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz"; - sha512 = "JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw=="; + version = "2.13.2"; + src = fetchurl { + url = "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz"; + sha512 = "TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="; }; }; "nanomatch-1.2.13" = { @@ -4784,13 +4802,13 @@ let sha512 = "fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA=="; }; }; - "neo-async-2.6.0" = { + "neo-async-2.6.1" = { name = "neo-async"; packageName = "neo-async"; - version = "2.6.0"; - src = fetchurl { - url = "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz"; - sha512 = "MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA=="; + version = "2.6.1"; + src = fetchurl { + url = "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz"; + sha512 = "iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="; }; }; "nice-try-1.0.5" = { @@ -4955,13 +4973,13 @@ let sha1 = "7e7d858b781bd7c991a41ba975ed3812754e998c"; }; }; - "object-keys-1.1.0" = { + "object-keys-1.1.1" = { name = "object-keys"; packageName = "object-keys"; - version = "1.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz"; - sha512 = "6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg=="; + version = "1.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"; + sha512 = "NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="; }; }; "object-visit-1.0.1" = { @@ -5081,13 +5099,13 @@ let sha1 = "3fbcfb15b899a44123b34b6dcc18b724336a2cae"; }; }; - "p-is-promise-2.0.0" = { + "p-is-promise-2.1.0" = { name = "p-is-promise"; packageName = "p-is-promise"; - version = "2.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz"; - sha512 = "pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg=="; + version = "2.1.0"; + src = fetchurl { + url = "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz"; + sha512 = "Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="; }; }; "p-limit-1.3.0" = { @@ -5099,13 +5117,13 @@ let sha512 = "vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="; }; }; - "p-limit-2.1.0" = { + "p-limit-2.2.0" = { name = "p-limit"; packageName = "p-limit"; - version = "2.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz"; - sha512 = "NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g=="; + version = "2.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz"; + sha512 = "pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ=="; }; }; "p-locate-2.0.0" = { @@ -5135,22 +5153,22 @@ let sha1 = "cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"; }; }; - "p-try-2.0.0" = { + "p-try-2.2.0" = { name = "p-try"; packageName = "p-try"; - version = "2.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz"; - sha512 = "hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ=="; - }; - }; - "pako-1.0.8" = { + version = "2.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"; + sha512 = "R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="; + }; + }; + "pako-1.0.10" = { name = "pako"; packageName = "pako"; - version = "1.0.8"; - src = fetchurl { - url = "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz"; - sha512 = "6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA=="; + version = "1.0.10"; + src = fetchurl { + url = "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz"; + sha512 = "0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw=="; }; }; "parallel-transform-1.1.0" = { @@ -6134,13 +6152,13 @@ let sha1 = "97f717b69d48784f5f526a6c5aa8ffdda055a4d1"; }; }; - "resolve-1.10.0" = { + "resolve-1.10.1" = { name = "resolve"; packageName = "resolve"; - version = "1.10.0"; - src = fetchurl { - url = "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz"; - sha512 = "3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg=="; + version = "1.10.1"; + src = fetchurl { + url = "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz"; + sha512 = "KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA=="; }; }; "resolve-cwd-2.0.0" = { @@ -6287,22 +6305,22 @@ let sha1 = "0e7350acdec80b1108528786ec1d4418d11b396d"; }; }; - "semver-5.6.0" = { + "semver-5.7.0" = { name = "semver"; packageName = "semver"; - version = "5.6.0"; - src = fetchurl { - url = "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz"; - sha512 = "RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="; - }; - }; - "serialize-javascript-1.6.1" = { + version = "5.7.0"; + src = fetchurl { + url = "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz"; + sha512 = "Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="; + }; + }; + "serialize-javascript-1.7.0" = { name = "serialize-javascript"; packageName = "serialize-javascript"; - version = "1.6.1"; - src = fetchurl { - url = "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz"; - sha512 = "A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw=="; + version = "1.7.0"; + src = fetchurl { + url = "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz"; + sha512 = "ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA=="; }; }; "set-blocking-2.0.0" = { @@ -6791,13 +6809,13 @@ let sha512 = "2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A=="; }; }; - "tapable-1.1.1" = { + "tapable-1.1.3" = { name = "tapable"; packageName = "tapable"; - version = "1.1.1"; - src = fetchurl { - url = "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz"; - sha512 = "9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA=="; + version = "1.1.3"; + src = fetchurl { + url = "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz"; + sha512 = "4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="; }; }; "through-2.3.8" = { @@ -6989,13 +7007,13 @@ let sha1 = "29c5733148057bb4e1f75df35b7a9cb72e6a59dd"; }; }; - "uglify-js-3.4.9" = { + "uglify-js-3.4.10" = { name = "uglify-js"; packageName = "uglify-js"; - version = "3.4.9"; - src = fetchurl { - url = "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz"; - sha512 = "8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q=="; + version = "3.4.10"; + src = fetchurl { + url = "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz"; + sha512 = "Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw=="; }; }; "uglify-to-browserify-1.0.2" = { @@ -7115,13 +7133,13 @@ let sha1 = "8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"; }; }; - "upath-1.1.0" = { + "upath-1.1.2" = { name = "upath"; packageName = "upath"; - version = "1.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz"; - sha512 = "bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw=="; + version = "1.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz"; + sha512 = "kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q=="; }; }; "upper-case-1.1.3" = { @@ -7223,31 +7241,31 @@ let sha512 = "yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="; }; }; - "v8-compile-cache-2.0.2" = { + "v8-compile-cache-2.0.3" = { name = "v8-compile-cache"; packageName = "v8-compile-cache"; - version = "2.0.2"; - src = fetchurl { - url = "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz"; - sha512 = "1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw=="; - }; - }; - "v8flags-3.1.2" = { + version = "2.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz"; + sha512 = "CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w=="; + }; + }; + "v8flags-3.1.3" = { name = "v8flags"; packageName = "v8flags"; - version = "3.1.2"; - src = fetchurl { - url = "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz"; - sha512 = "MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw=="; - }; - }; - "vendors-1.0.2" = { + version = "3.1.3"; + src = fetchurl { + url = "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz"; + sha512 = "amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w=="; + }; + }; + "vendors-1.0.3" = { name = "vendors"; packageName = "vendors"; - version = "1.0.2"; - src = fetchurl { - url = "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz"; - sha512 = "w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ=="; + version = "1.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz"; + sha512 = "fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw=="; }; }; "verror-1.10.0" = { @@ -7385,13 +7403,13 @@ let sha1 = "b79669bb42ecb409f83d583cad52ca17eaa1643f"; }; }; - "worker-farm-1.6.0" = { + "worker-farm-1.7.0" = { name = "worker-farm"; packageName = "worker-farm"; - version = "1.6.0"; - src = fetchurl { - url = "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz"; - sha512 = "6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ=="; + version = "1.7.0"; + src = fetchurl { + url = "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz"; + sha512 = "rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw=="; }; }; "wrap-ansi-2.1.0" = { @@ -7496,9 +7514,9 @@ let sources."@polymer/paper-toast-3.0.1" sources."@polymer/paper-toggle-button-3.0.1" sources."@polymer/paper-tooltip-3.0.1" - sources."@polymer/polymer-3.1.0" + sources."@polymer/polymer-3.2.0" sources."@types/clone-0.1.30" - sources."@types/node-6.14.3" + sources."@types/node-6.14.6" sources."@types/parse5-2.2.34" sources."@webassemblyjs/ast-1.7.10" sources."@webassemblyjs/floating-point-hex-parser-1.7.10" @@ -7518,8 +7536,8 @@ let sources."@webassemblyjs/wasm-parser-1.7.10" sources."@webassemblyjs/wast-parser-1.7.10" sources."@webassemblyjs/wast-printer-1.7.10" - sources."@webcomponents/shadycss-1.9.0" - sources."@webcomponents/webcomponentsjs-2.2.7" + sources."@webcomponents/shadycss-1.9.1" + sources."@webcomponents/webcomponentsjs-2.2.10" sources."@xtuc/ieee754-1.2.0" sources."@xtuc/long-4.2.1" sources."abbrev-1.1.1" @@ -7564,7 +7582,7 @@ let sources."asap-2.0.6" sources."asn1-0.2.4" sources."asn1.js-4.10.1" - (sources."assert-1.4.1" // { + (sources."assert-1.5.0" // { dependencies = [ sources."inherits-2.0.1" sources."util-0.10.3" @@ -7574,7 +7592,7 @@ let sources."assign-symbols-1.0.0" sources."ast-types-0.9.6" sources."async-0.1.22" - sources."async-each-1.0.1" + sources."async-each-1.0.3" sources."asynckit-0.4.0" sources."atob-2.1.2" (sources."autoprefixer-6.7.7" // { @@ -7696,8 +7714,8 @@ let sources."base64-js-1.3.0" sources."bcrypt-pbkdf-1.0.2" sources."big.js-5.2.2" - sources."binary-extensions-1.13.0" - sources."bluebird-3.5.3" + sources."binary-extensions-1.13.1" + sources."bluebird-3.5.4" sources."bn.js-4.11.8" sources."boolbase-1.0.0" sources."boom-2.10.1" @@ -7721,7 +7739,7 @@ let sources."builtin-status-codes-3.0.0" (sources."cacache-10.0.4" // { dependencies = [ - sources."glob-7.1.3" + sources."glob-7.1.4" sources."graceful-fs-4.1.15" sources."lru-cache-4.1.5" sources."minimatch-3.0.4" @@ -7730,20 +7748,20 @@ let }) sources."cache-base-1.0.1" sources."camel-case-3.0.0" - sources."camelcase-5.0.0" + sources."camelcase-5.3.1" (sources."caniuse-api-1.6.1" // { dependencies = [ sources."browserslist-1.7.7" ]; }) - sources."caniuse-db-1.0.30000939" - sources."caniuse-lite-1.0.30000939" + sources."caniuse-db-1.0.30000967" + sources."caniuse-lite-1.0.30000967" sources."caseless-0.12.0" sources."center-align-0.1.3" sources."chalk-0.5.1" - (sources."chokidar-2.1.2" // { - dependencies = [ - sources."is-glob-4.0.0" + (sources."chokidar-2.1.5" // { + dependencies = [ + sources."is-glob-4.0.1" ]; }) sources."chownr-1.1.1" @@ -7783,7 +7801,7 @@ let }) (sources."cli-1.0.1" // { dependencies = [ - sources."glob-7.1.3" + sources."glob-7.1.4" sources."minimatch-3.0.4" ]; }) @@ -7806,10 +7824,10 @@ let sources."color-string-0.3.0" sources."colormin-1.1.2" sources."colors-0.6.2" - sources."combined-stream-1.0.7" + sources."combined-stream-1.0.8" sources."commander-2.14.1" sources."commondir-1.0.1" - sources."component-emitter-1.2.1" + sources."component-emitter-1.3.0" sources."concat-map-0.0.1" (sources."concat-stream-1.6.2" // { dependencies = [ @@ -7822,7 +7840,7 @@ let sources."convert-source-map-1.6.0" (sources."copy-concurrently-1.0.5" // { dependencies = [ - sources."glob-7.1.3" + sources."glob-7.1.4" sources."minimatch-3.0.4" sources."rimraf-2.6.3" ]; @@ -7830,7 +7848,7 @@ let sources."copy-descriptor-0.1.1" (sources."copy-webpack-plugin-4.6.0" // { dependencies = [ - sources."is-glob-4.0.0" + sources."is-glob-4.0.1" sources."minimatch-3.0.4" ]; }) @@ -7896,6 +7914,7 @@ let sources."domelementtype-1.3.1" sources."domhandler-2.3.0" sources."domutils-1.5.1" + sources."dropzone-5.5.1" (sources."duplexify-3.7.1" // { dependencies = [ sources."readable-stream-2.3.6" @@ -7903,7 +7922,7 @@ let ]; }) sources."ecc-jsbn-0.1.2" - sources."electron-to-chromium-1.3.113" + sources."electron-to-chromium-1.3.133" sources."elliptic-6.4.1" sources."emojis-list-2.1.0" sources."end-of-stream-1.4.1" @@ -7918,7 +7937,7 @@ let sources."es-to-primitive-1.2.0" sources."es6-templates-0.2.3" sources."escape-string-regexp-1.0.5" - sources."eslint-scope-4.0.0" + sources."eslint-scope-4.0.3" sources."espree-3.5.4" sources."esprima-1.0.4" sources."esrecurse-4.2.1" @@ -7982,7 +8001,7 @@ let sources."minimatch-0.3.0" ]; }) - sources."fined-1.1.1" + sources."fined-1.2.0" sources."flagged-respawn-1.0.1" sources."flatten-1.0.2" (sources."flush-write-stream-1.1.1" // { @@ -8008,7 +8027,7 @@ let ]; }) sources."fs.realpath-1.0.0" - sources."fsevents-1.2.7" + sources."fsevents-1.2.9" sources."function-bind-1.1.1" sources."gaze-0.5.2" sources."get-caller-file-1.0.3" @@ -8040,7 +8059,7 @@ let sources."globals-9.18.0" (sources."globby-7.1.1" // { dependencies = [ - sources."glob-7.1.3" + sources."glob-7.1.4" sources."minimatch-3.0.4" ]; }) @@ -8166,7 +8185,7 @@ let sources."supports-color-5.5.0" ]; }) - sources."ieee754-1.1.12" + sources."ieee754-1.1.13" sources."iferr-0.1.5" sources."ignore-3.3.10" sources."image-size-0.5.5" @@ -8174,9 +8193,9 @@ let dependencies = [ sources."find-up-3.0.0" sources."locate-path-3.0.0" - sources."p-limit-2.1.0" + sources."p-limit-2.2.0" sources."p-locate-3.0.0" - sources."p-try-2.0.0" + sources."p-try-2.2.0" sources."pkg-dir-3.0.0" ]; }) @@ -8229,7 +8248,7 @@ let sources."js-yaml-2.0.5" sources."jsbn-0.1.1" sources."jsesc-1.3.0" - (sources."jshint-2.10.1" // { + (sources."jshint-2.10.2" // { dependencies = [ sources."lodash-4.17.11" sources."minimatch-3.0.4" @@ -8280,7 +8299,7 @@ let sources."mark.js-8.11.1" sources."math-expression-evaluator-1.2.17" sources."md5.js-1.3.5" - sources."mem-4.1.0" + sources."mem-4.3.0" (sources."memory-fs-0.4.1" // { dependencies = [ sources."readable-stream-2.3.6" @@ -8290,9 +8309,9 @@ let sources."micromatch-3.1.10" sources."miller-rabin-4.0.1" sources."mime-1.6.0" - sources."mime-db-1.38.0" - sources."mime-types-2.1.22" - sources."mimic-fn-1.2.0" + sources."mime-db-1.40.0" + sources."mime-types-2.1.24" + sources."mimic-fn-2.1.0" sources."minimalistic-assert-1.0.1" sources."minimalistic-crypto-utils-1.0.1" sources."minimatch-0.2.14" @@ -8309,18 +8328,18 @@ let ]; }) sources."moment-2.24.0" - sources."mousetrap-1.6.2" + sources."mousetrap-1.6.3" (sources."move-concurrently-1.0.1" // { dependencies = [ - sources."glob-7.1.3" + sources."glob-7.1.4" sources."minimatch-3.0.4" sources."rimraf-2.6.3" ]; }) sources."ms-2.0.0" - sources."nan-2.12.1" + sources."nan-2.13.2" sources."nanomatch-1.2.13" - sources."neo-async-2.6.0" + sources."neo-async-2.6.1" sources."nice-try-1.0.5" sources."no-case-2.3.2" (sources."node-libs-browser-2.2.0" // { @@ -8361,7 +8380,7 @@ let sources."kind-of-3.2.2" ]; }) - sources."object-keys-1.1.0" + sources."object-keys-1.1.1" sources."object-visit-1.0.1" sources."object.defaults-1.1.0" sources."object.getownpropertydescriptors-2.0.3" @@ -8375,11 +8394,11 @@ let sources."osenv-0.1.5" sources."p-defer-1.0.0" sources."p-finally-1.0.0" - sources."p-is-promise-2.0.0" + sources."p-is-promise-2.1.0" sources."p-limit-1.3.0" sources."p-locate-2.0.0" sources."p-try-1.0.0" - sources."pako-1.0.8" + sources."pako-1.0.10" (sources."parallel-transform-1.1.0" // { dependencies = [ sources."readable-stream-2.3.6" @@ -8582,7 +8601,7 @@ let sources."request-2.81.0" sources."require-directory-2.1.1" sources."require-main-filename-1.0.1" - sources."resolve-1.10.0" + sources."resolve-1.10.1" sources."resolve-cwd-2.0.0" sources."resolve-dir-1.0.1" sources."resolve-from-3.0.0" @@ -8598,12 +8617,12 @@ let sources."sax-1.2.4" (sources."schema-utils-0.4.7" // { dependencies = [ - sources."ajv-6.9.2" + sources."ajv-6.10.0" ]; }) sources."select-1.1.2" - sources."semver-5.6.0" - sources."serialize-javascript-1.6.1" + sources."semver-5.7.0" + sources."serialize-javascript-1.7.0" sources."set-blocking-2.0.0" (sources."set-value-2.0.0" // { dependencies = [ @@ -8716,7 +8735,7 @@ let sources."js-yaml-3.7.0" ]; }) - sources."tapable-1.1.1" + sources."tapable-1.1.3" sources."through-2.3.8" (sources."through2-2.0.5" // { dependencies = [ @@ -8765,9 +8784,9 @@ let sources."source-map-0.6.1" ]; }) - (sources."uglify-js-3.4.9" // { - dependencies = [ - sources."commander-2.17.1" + (sources."uglify-js-3.4.10" // { + dependencies = [ + sources."commander-2.19.0" sources."source-map-0.6.1" ]; }) @@ -8800,7 +8819,7 @@ let sources."has-values-0.1.4" ]; }) - sources."upath-1.1.0" + sources."upath-1.1.2" sources."upper-case-1.1.3" (sources."uri-js-4.2.2" // { dependencies = [ @@ -8819,9 +8838,9 @@ let sources."util.promisify-1.0.0" sources."utila-0.4.0" sources."uuid-3.3.2" - sources."v8-compile-cache-2.0.2" - sources."v8flags-3.1.2" - sources."vendors-1.0.2" + sources."v8-compile-cache-2.0.3" + sources."v8flags-3.1.3" + sources."vendors-1.0.3" (sources."verror-1.10.0" // { dependencies = [ sources."assert-plus-1.0.0" @@ -8836,7 +8855,7 @@ let sources."waypoints-4.0.1" (sources."webpack-4.23.1" // { dependencies = [ - sources."ajv-6.9.2" + sources."ajv-6.10.0" ]; }) (sources."webpack-cli-3.1.2" // { @@ -8876,7 +8895,7 @@ let sources."which-module-2.0.0" sources."window-size-0.1.0" sources."wordwrap-0.0.2" - sources."worker-farm-1.6.0" + sources."worker-farm-1.7.0" (sources."wrap-ansi-2.1.0" // { dependencies = [ sources."ansi-regex-2.1.1" @@ -8892,9 +8911,9 @@ let dependencies = [ sources."find-up-3.0.0" sources."locate-path-3.0.0" - sources."p-limit-2.1.0" + sources."p-limit-2.2.0" sources."p-locate-3.0.0" - sources."p-try-2.0.0" + sources."p-try-2.2.0" ]; }) sources."yargs-parser-11.1.1" diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix --- a/pkgs/python-packages.nix +++ b/pkgs/python-packages.nix @@ -88,8 +88,8 @@ self: super: { name = "authomatic-0.1.0.post1"; doCheck = false; src = fetchurl { - url = "https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801"; - sha256 = "1cgk0a86sbsjbri06gf5z5l4npwkjdxw6fdnwl4vvfmxs2sx9yxw"; + url = "https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383"; + sha256 = "0pc716mva0ym6xd8jwzjbjp8dqxy9069wwwv2aqwb8lyhl4757ab"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -277,8 +277,8 @@ self: super: { self."six" ]; src = fetchurl { - url = "https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c"; - sha256 = "1hhcxirwvg58grlfr177b3awhbq8hlx1l3lh69ifl1ki7lfd1s1x"; + url = "https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626"; + sha256 = "0kqfrdfr14mw8yd8qwq14dv2xghpkjmd3yjsy8dfcbvpcc17xnxp"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -442,11 +442,11 @@ self: super: { }; }; "ecdsa" = super.buildPythonPackage { - name = "ecdsa-0.13"; + name = "ecdsa-0.13.2"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz"; - sha256 = "1yj31j0asmrx4an9xvsaj2icdmzy6pw0glfpqrrkrphwdpi1xkv4"; + url = "https://files.pythonhosted.org/packages/51/76/139bf6e9b7b6684d5891212cdbd9e0739f2bfc03f380a1a6ffa700f392ac/ecdsa-0.13.2.tar.gz"; + sha256 = "116qaq7bh4lcynzi613960jhsnn19v0kmsqwahiwjfj14gx4y0sw"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -534,8 +534,8 @@ self: super: { self."configparser" ]; src = fetchurl { - url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313"; - sha256 = "0bihrdp8ahsys437kxdhk52gz6kib8rxjv71i93wkw7594fcaxll"; + url = "https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d"; + sha256 = "0qih72n2myclanplqipqxpgpj9d2yhff1pz5d02zq1cfqyd173w5"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -845,14 +845,14 @@ self: super: { }; }; "jupyter-core" = super.buildPythonPackage { - name = "jupyter-core-4.4.0"; + name = "jupyter-core-4.5.0"; doCheck = false; propagatedBuildInputs = [ self."traitlets" ]; src = fetchurl { - url = "https://files.pythonhosted.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz"; - sha256 = "1dy083rarba8prn9f9srxq3c7n7vyql02ycrqq306c40lr57aw5s"; + url = "https://files.pythonhosted.org/packages/4a/de/ff4ca734656d17ebe0450807b59d728f45277e2e7f4b82bc9aae6cb82961/jupyter_core-4.5.0.tar.gz"; + sha256 = "1xr4pbghwk5hayn5wwnhb7z95380r45p79gf5if5pi1akwg7qvic"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1092,15 +1092,15 @@ self: super: { }; }; "pathlib2" = super.buildPythonPackage { - name = "pathlib2-2.3.3"; + name = "pathlib2-2.3.4"; doCheck = false; propagatedBuildInputs = [ self."six" self."scandir" ]; src = fetchurl { - url = "https://files.pythonhosted.org/packages/bf/d7/a2568f4596b75d2c6e2b4094a7e64f620decc7887f69a1f2811931ea15b9/pathlib2-2.3.3.tar.gz"; - sha256 = "0hpp92vqqgcd8h92msm9slv161b1q160igjwnkf2ag6cx0c96695"; + url = "https://files.pythonhosted.org/packages/b5/f4/9c7cc726ece2498b6c8b62d3262aa43f59039b953fe23c9964ac5e18d40b/pathlib2-2.3.4.tar.gz"; + sha256 = "1y0f9rkm1924zrc5dn4bwxlhgdkbml82lkcc28l5rgmr7d918q24"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1212,11 +1212,11 @@ self: super: { }; }; "psycopg2" = super.buildPythonPackage { - name = "psycopg2-2.8.2"; + name = "psycopg2-2.8.3"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/23/7e/93c325482c328619870b6cd09370f6dbe1148283daca65115cd63642e60f/psycopg2-2.8.2.tar.gz"; - sha256 = "122mn2z3r0zgs8jyq682jjjr6vq5690qmxqf22gj6g41dwdz5b2w"; + url = "https://files.pythonhosted.org/packages/5c/1c/6997288da181277a0c29bc39a5f9143ff20b8c99f2a7d059cfb55163e165/psycopg2-2.8.3.tar.gz"; + sha256 = "0ms4kx0p5n281l89awccix4d05ybmdngnjjpi9jbzd0rhf1nwyl9"; }; meta = { license = [ pkgs.lib.licenses.zpl21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ]; @@ -1329,11 +1329,11 @@ self: super: { }; }; "pygments" = super.buildPythonPackage { - name = "pygments-2.3.1"; + name = "pygments-2.4.2"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/64/69/413708eaf3a64a6abb8972644e0f20891a55e621c6759e2c3f3891e05d63/Pygments-2.3.1.tar.gz"; - sha256 = "0ji87g09jph8jqcvclgb02qvxasdnr9pzvk90rl66d90yqcxmyjz"; + url = "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz"; + sha256 = "15v2sqm5g12bqa0c7wikfh9ck2nl97ayizy1hpqhmws5gqalq748"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1395,21 +1395,6 @@ self: super: { license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; }; }; - "pyramid-beaker" = super.buildPythonPackage { - name = "pyramid-beaker-0.8"; - doCheck = false; - propagatedBuildInputs = [ - self."pyramid" - self."beaker" - ]; - src = fetchurl { - url = "https://files.pythonhosted.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz"; - sha256 = "0hflx3qkcdml1mwpq53sz46s7jickpfn0zy0ns2c7j445j66bp3p"; - }; - meta = { - license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; - }; - }; "pyramid-debugtoolbar" = super.buildPythonPackage { name = "pyramid-debugtoolbar-4.5"; doCheck = false; @@ -1783,6 +1768,7 @@ self: super: { self."msgpack-python" self."pyotp" self."packaging" + self."pathlib2" self."paste" self."pastedeploy" self."pastescript" @@ -1793,7 +1779,6 @@ self: super: { self."pycrypto" self."pygments" self."pyparsing" - self."pyramid-beaker" self."pyramid-debugtoolbar" self."pyramid-mako" self."pyramid" @@ -1886,8 +1871,8 @@ self: super: { self."elasticsearch1-dsl" ]; src = fetchurl { - url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28"; - sha256 = "1k8l3s4mvshza1zay6dfxprq54fyb5dc85dqdva9wa3f466y0adk"; + url = "https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661"; + sha256 = "1vfhgf46inbx7jvlfx4fdzh3vz7lh37r291gzb5hx447pfm3qllg"; }; meta = { license = [ { fullName = "Apache 2.0 and Proprietary"; } ]; @@ -2001,25 +1986,25 @@ self: super: { }; }; "subprocess32" = super.buildPythonPackage { - name = "subprocess32-3.5.3"; + name = "subprocess32-3.5.4"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/be/2b/beeba583e9877e64db10b52a96915afc0feabf7144dcbf2a0d0ea68bf73d/subprocess32-3.5.3.tar.gz"; - sha256 = "1hr5fan8i719hmlmz73hf8rhq74014w07d8ryg7krvvf6692kj3b"; + url = "https://files.pythonhosted.org/packages/32/c8/564be4d12629b912ea431f1a50eb8b3b9d00f1a0b1ceff17f266be190007/subprocess32-3.5.4.tar.gz"; + sha256 = "17f7mvwx2271s1wrl0qac3wjqqnrqag866zs3qc8v5wp0k43fagb"; }; meta = { license = [ pkgs.lib.licenses.psfl ]; }; }; "supervisor" = super.buildPythonPackage { - name = "supervisor-4.0.2"; + name = "supervisor-4.0.3"; doCheck = false; propagatedBuildInputs = [ self."meld3" ]; src = fetchurl { - url = "https://files.pythonhosted.org/packages/cb/02/95953c98a770803e42009f18c2eb361bc035ab6fb3cbb442ffcc94387eac/supervisor-4.0.2.tar.gz"; - sha256 = "0xg5c41wd51wnf2ihc47gwkwjf29zq2q44lcwx8di2gvliyla12n"; + url = "https://files.pythonhosted.org/packages/97/48/f38bf70bd9282d1a18d591616557cc1a77a1c627d57dff66ead65c891dc8/supervisor-4.0.3.tar.gz"; + sha256 = "17hla7mx6w5m5jzkkjxgqa8wpswqmfhbhf49f692hw78fg0ans7p"; }; meta = { license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; @@ -2159,11 +2144,11 @@ self: super: { }; }; "waitress" = super.buildPythonPackage { - name = "waitress-1.1.0"; + name = "waitress-1.3.0"; doCheck = false; src = fetchurl { - url = "https://files.pythonhosted.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz"; - sha256 = "1a85gyji0kajc3p0s1pwwfm06w4wfxjkvvl4rnrz3h164kbd6g6k"; + url = "https://files.pythonhosted.org/packages/43/50/9890471320d5ad22761ae46661cf745f487b1c8c4ec49352b99e1078b970/waitress-1.3.0.tar.gz"; + sha256 = "09j5dzbbcxib7vdskhx39s1qsydlr4n2p2png71d7mjnr9pnwajf"; }; meta = { license = [ pkgs.lib.licenses.zpl21 ]; diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ amqp==2.3.1 # not released authomatic that has updated some oauth providers -https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1 +https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383#egg=authomatic==0.1.0.post1 babel==1.3 beaker==1.9.1 @@ -12,7 +12,7 @@ channelstream==0.5.2 click==7.0 colander==1.7.0 # our custom configobj -https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c#egg=configobj==5.0.6 +https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626#egg=configobj==5.0.6 cssselect==1.0.3 cryptography==2.6.1 decorator==4.1.2 @@ -34,6 +34,7 @@ markupsafe==1.1.0 msgpack-python==0.5.6 pyotp==2.2.7 packaging==15.2 +pathlib2==2.3.4 paste==3.0.8 pastedeploy==2.0.1 pastescript==3.1.0 @@ -42,9 +43,8 @@ psutil==5.5.1 py-bcrypt==0.4 pycurl==7.43.0.2 pycrypto==2.6.1 -pygments==2.3.1 +pygments==2.4.2 pyparsing==2.3.0 -pyramid-beaker==0.8 pyramid-debugtoolbar==4.5.0 pyramid-mako==1.0.2 pyramid==1.10.4 @@ -66,8 +66,8 @@ simplejson==3.16.0 six==1.11.0 sqlalchemy==1.1.18 sshpubkeys==3.1.0 -subprocess32==3.5.3 -supervisor==4.0.2 +subprocess32==3.5.4 +supervisor==4.0.3 translationstring==1.3 urllib3==1.24.1 urlobject==2.4.3 @@ -87,11 +87,11 @@ zope.interface==4.6.0 mysql-python==1.2.5 pymysql==0.8.1 pysqlite==2.8.3 -psycopg2==2.8.2 +psycopg2==2.8.3 # IPYTHON RENDERING # entrypoints backport, pypi version doesn't support egg installs -https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1 +https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d#egg=entrypoints==0.2.2.rhodecode-upstream1 nbconvert==5.3.1 nbformat==4.4.0 jupyter_client==5.0.0 @@ -105,14 +105,14 @@ bumpversion==0.5.3 gevent==1.4.0 greenlet==0.4.15 gunicorn==19.9.0 -waitress==1.1.0 +waitress==1.3.0 ## debug ipdb==0.12.0 ipython==5.1.0 ## rhodecode-tools, special case -https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28#egg=rhodecode-tools==1.2.1 +https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661#egg=rhodecode-tools==1.2.1 ## appenlight appenlight-client==0.6.26 diff --git a/requirements_pinned.txt b/requirements_pinned.txt --- a/requirements_pinned.txt +++ b/requirements_pinned.txt @@ -5,15 +5,15 @@ attrs==18.2.0 billiard==3.5.0.3 chameleon==2.24 cffi==1.12.2 -ecdsa==0.13 +ecdsa==0.13.2 hupper==1.6.1 gnureadline==6.3.8 jinja2==2.9.6 jsonschema==2.6.0 -pathlib2==2.3.3 pyramid-jinja2==2.7 +pluggy==0.11.0 setproctitle==1.1.10 scandir==1.10.0 tempita==0.5.2 vine==1.3.0 -configparser==3.7.4 \ No newline at end of file +configparser==3.7.4 diff --git a/rhodecode/__init__.py b/rhodecode/__init__.py --- a/rhodecode/__init__.py +++ b/rhodecode/__init__.py @@ -45,7 +45,7 @@ PYRAMID_SETTINGS = {} EXTENSIONS = {} __version__ = ('.'.join((str(each) for each in VERSION[:3]))) -__dbversion__ = 97 # defines current db version for migrations +__dbversion__ = 98 # defines current db version for migrations __platform__ = platform.system() __license__ = 'AGPLv3, and Commercial License' __author__ = 'RhodeCode GmbH' diff --git a/rhodecode/api/tests/test_comment_commit.py b/rhodecode/api/tests/test_comment_commit.py --- a/rhodecode/api/tests/test_comment_commit.py +++ b/rhodecode/api/tests/test_comment_commit.py @@ -37,11 +37,11 @@ class TestCommentCommit(object): assert_error(id_, expected, given=response.body) @pytest.mark.parametrize("commit_id, expected_err", [ - ('abcabca', {'hg': 'Commit {commit} does not exist for {repo}', - 'git': 'Commit {commit} does not exist for {repo}', + ('abcabca', {'hg': 'Commit {commit} does not exist for `{repo}`', + 'git': 'Commit {commit} does not exist for `{repo}`', 'svn': 'Commit id {commit} not understood.'}), - ('idontexist', {'hg': 'Commit {commit} does not exist for {repo}', - 'git': 'Commit {commit} does not exist for {repo}', + ('idontexist', {'hg': 'Commit {commit} does not exist for `{repo}`', + 'git': 'Commit {commit} does not exist for `{repo}`', 'svn': 'Commit id {commit} not understood.'}), ]) def test_api_comment_commit_wrong_hash(self, backend, commit_id, expected_err): @@ -53,7 +53,7 @@ class TestCommentCommit(object): expected_err = expected_err[backend.alias] expected_err = expected_err.format( - repo=backend.repo.scm_instance(), commit=commit_id) + repo=backend.repo.scm_instance().name, commit=commit_id) assert_error(id_, expected_err, given=response.body) @pytest.mark.parametrize("status_change, message, commit_id", [ diff --git a/rhodecode/api/tests/test_get_repo.py b/rhodecode/api/tests/test_get_repo.py --- a/rhodecode/api/tests/test_get_repo.py +++ b/rhodecode/api/tests/test_get_repo.py @@ -44,6 +44,7 @@ class TestGetRepo(object): self, apikey_attr, expect_secrets, cache_param, backend, user_util): repo = backend.create_repo() + repo_id = repo.repo_id usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) group = user_util.create_user_group(members=[usr]) user_util.grant_user_group_permission_to_repo( @@ -64,6 +65,8 @@ class TestGetRepo(object): permissions = expected_permissions(repo) followers = [] + + repo = RepoModel().get(repo_id) for user in repo.followers: followers.append(user.user.get_api_data( include_secrets=expect_secrets)) @@ -84,6 +87,7 @@ class TestGetRepo(object): # TODO: Depending on which tests are running before this one, we # start with a different number of permissions in the database. repo = RepoModel().get_by_repo_name(backend.repo_name) + repo_id = repo.repo_id permission_count = len(repo.repo_to_perm) RepoModel().grant_user_permission(repo=backend.repo_name, @@ -102,6 +106,8 @@ class TestGetRepo(object): permissions = expected_permissions(repo) followers = [] + + repo = RepoModel().get(repo_id) for user in repo.followers: followers.append(user.user.get_api_data()) diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py --- a/rhodecode/api/views/repo_api.py +++ b/rhodecode/api/views/repo_api.py @@ -444,7 +444,7 @@ def get_repo_nodes(request, apiuser, rep result: [ { "binary": false, - "content": "File line\nLine2\n", + "content": "File line", "extension": "md", "lines": 2, "md5": "059fa5d29b19c0657e384749480f6422", @@ -529,6 +529,7 @@ def get_repo_file(request, apiuser, repo :param cache: Use internal caches for fetching files. If disabled fetching files is slower but more memory efficient :type cache: Optional(bool) + Example output: .. code-block:: bash diff --git a/rhodecode/apps/_base/__init__.py b/rhodecode/apps/_base/__init__.py --- a/rhodecode/apps/_base/__init__.py +++ b/rhodecode/apps/_base/__init__.py @@ -168,6 +168,28 @@ class BaseAppView(object): from rhodecode.lib.base import attach_context_attributes attach_context_attributes(c, self.request, self.request.user.user_id) + c.is_super_admin = c.auth_user.is_admin + + c.can_create_repo = c.is_super_admin + c.can_create_repo_group = c.is_super_admin + c.can_create_user_group = c.is_super_admin + + c.is_delegated_admin = False + + if not c.auth_user.is_default and not c.is_super_admin: + c.can_create_repo = h.HasPermissionAny('hg.create.repository')( + user=self.request.user) + repositories = c.auth_user.repositories_admin or c.can_create_repo + + c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')( + user=self.request.user) + repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group + + c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')( + user=self.request.user) + user_groups = c.auth_user.user_groups_admin or c.can_create_user_group + # delegated admin can create, or manage some objects + c.is_delegated_admin = repositories or repository_groups or user_groups return c def _get_template_context(self, tmpl_args, **kwargs): @@ -215,12 +237,17 @@ class RepoAppView(BaseAppView): c.rhodecode_db_repo = self.db_repo c.repo_name = self.db_repo_name c.repository_pull_requests = self.db_repo_pull_requests + c.repository_is_user_following = ScmModel().is_following_repo( + self.db_repo_name, self._rhodecode_user.user_id) self.path_filter = PathFilter(None) c.repository_requirements_missing = {} try: self.rhodecode_vcs_repo = self.db_repo.scm_instance() - if self.rhodecode_vcs_repo: + # NOTE(marcink): + # comparison to None since if it's an object __bool__ is expensive to + # calculate + if self.rhodecode_vcs_repo is not None: path_perms = self.rhodecode_vcs_repo.get_path_permissions( c.auth_user.username) self.path_filter = PathFilter(path_perms) diff --git a/rhodecode/apps/_base/navigation.py b/rhodecode/apps/_base/navigation.py --- a/rhodecode/apps/_base/navigation.py +++ b/rhodecode/apps/_base/navigation.py @@ -85,8 +85,6 @@ class NavigationRegistry(object): 'admin_settings_hooks'), NavEntry('search', _('Full Text Search'), 'admin_settings_search'), - NavEntry('integrations', _('Integrations'), - 'global_integrations_home'), NavEntry('system', _('System Info'), 'admin_settings_system'), NavEntry('exceptions', _('Exceptions Tracker'), diff --git a/rhodecode/apps/admin/tests/test_admin_main_views.py b/rhodecode/apps/admin/tests/test_admin_main_views.py --- a/rhodecode/apps/admin/tests/test_admin_main_views.py +++ b/rhodecode/apps/admin/tests/test_admin_main_views.py @@ -46,10 +46,10 @@ def route_path(name, params=None, **kwar class TestAdminMainView(TestController): - def test_redirect_admin_home(self): + def test_access_admin_home(self): self.log_user() - response = self.app.get(route_path('admin_home'), status=302) - assert response.location.endswith('/audit_logs') + response = self.app.get(route_path('admin_home'), status=200) + response.mustcontain("Administration area") def test_redirect_pull_request_view(self, view): self.log_user() diff --git a/rhodecode/apps/admin/views/main_views.py b/rhodecode/apps/admin/views/main_views.py --- a/rhodecode/apps/admin/views/main_views.py +++ b/rhodecode/apps/admin/views/main_views.py @@ -20,12 +20,12 @@ import logging -from pyramid.httpexceptions import HTTPFound +from pyramid.httpexceptions import HTTPFound, HTTPNotFound from pyramid.view import view_config from rhodecode.apps._base import BaseAppView from rhodecode.lib import helpers as h -from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator) +from rhodecode.lib.auth import (LoginRequired, NotAnonymous) from rhodecode.model.db import PullRequest @@ -33,14 +33,23 @@ log = logging.getLogger(__name__) class AdminMainView(BaseAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + return c @LoginRequired() - @HasPermissionAllDecorator('hg.admin') + @NotAnonymous() @view_config( - route_name='admin_home', request_method='GET') + route_name='admin_home', request_method='GET', + renderer='rhodecode:templates/admin/main.mako') def admin_main(self): - # redirect _admin to audit logs... - raise HTTPFound(h.route_path('admin_audit_logs')) + c = self.load_default_context() + c.active = 'admin' + + if not (c.is_super_admin or c.is_delegated_admin): + raise HTTPNotFound() + + return self._get_template_context(c) @LoginRequired() @view_config(route_name='pull_requests_global_0', request_method='GET') @@ -49,8 +58,7 @@ class AdminMainView(BaseAppView): def pull_requests(self): """ Global redirect for Pull Requests - - :param pull_request_id: id of pull requests in the system + pull_request_id: id of pull requests in the system """ pull_request = PullRequest.get_or_404( diff --git a/rhodecode/apps/file_store/local_store.py b/rhodecode/apps/file_store/local_store.py --- a/rhodecode/apps/file_store/local_store.py +++ b/rhodecode/apps/file_store/local_store.py @@ -38,19 +38,18 @@ class LocalFileStorage(object): """ Resolves a unique name and the correct path. If a filename for that path already exists then a numeric prefix with values > 0 will be - added, for example test.jpg -> test-1.jpg etc. initially file would have 0 prefix. + added, for example test.jpg -> 1-test.jpg etc. initially file would have 0 prefix. :param name: base name of file :param directory: absolute directory path """ - basename, ext = os.path.splitext(name) counter = 0 while True: - name = '%s-%d%s' % (basename, counter, ext) + name = '%d-%s' % (counter, name) # sub_store prefix to optimize disk usage, e.g some_path/ab/final_file - sub_store = cls._sub_store_from_filename(basename) + sub_store = cls._sub_store_from_filename(name) sub_store_path = os.path.join(directory, sub_store) if not os.path.exists(sub_store_path): os.makedirs(sub_store_path) @@ -209,3 +208,16 @@ class LocalFileStorage(object): filename = os.path.join(directory, filename) return filename, metadata + + def get_metadata(self, filename): + """ + Reads JSON stored metadata for a file + + :param filename: + :return: + """ + filename = self.store_path(filename) + filename_meta = filename + '.meta' + + with open(filename_meta, "rb") as source_meta: + return json.loads(source_meta.read()) diff --git a/rhodecode/apps/file_store/tests/test_upload_file.py b/rhodecode/apps/file_store/tests/test_upload_file.py --- a/rhodecode/apps/file_store/tests/test_upload_file.py +++ b/rhodecode/apps/file_store/tests/test_upload_file.py @@ -21,6 +21,7 @@ import os import pytest from rhodecode.lib.ext_json import json +from rhodecode.model.db import Session, FileStore from rhodecode.tests import TestController from rhodecode.apps.file_store import utils, config_keys @@ -46,9 +47,12 @@ class TestFileStoreViews(TestController) ('abcde-0.exe', "1234567", True), ('abcde-0.jpg', "xxxxx", False), ]) - def test_get_files_from_store(self, fid, content, exists, tmpdir): - self.log_user() + def test_get_files_from_store(self, fid, content, exists, tmpdir, user_util): + user = self.log_user() + user_id = user['user_id'] + repo_id = user_util.create_repo().repo_id store_path = self.app._pyramid_settings[config_keys.store_path] + store_uid = fid if exists: status = 200 @@ -58,17 +62,28 @@ class TestFileStoreViews(TestController) f.write(content) with open(filesystem_file, 'rb') as f: - fid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid}) + store_uid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid}) + + entry = FileStore.create( + file_uid=store_uid, filename=metadata["filename"], + file_hash=metadata["sha256"], file_size=metadata["size"], + file_display_name='file_display_name', + file_description='repo artifact `{}`'.format(metadata["filename"]), + check_acl=True, user_id=user_id, + scope_repo_id=repo_id + ) + Session().add(entry) + Session().commit() else: status = 404 - response = self.app.get(route_path('download_file', fid=fid), status=status) + response = self.app.get(route_path('download_file', fid=store_uid), status=status) if exists: assert response.text == content - file_store_path = os.path.dirname(store.resolve_name(fid, store_path)[1]) - metadata_file = os.path.join(file_store_path, fid + '.meta') + file_store_path = os.path.dirname(store.resolve_name(store_uid, store_path)[1]) + metadata_file = os.path.join(file_store_path, store_uid + '.meta') assert os.path.exists(metadata_file) with open(metadata_file, 'rb') as f: json_data = json.loads(f.read()) diff --git a/rhodecode/apps/file_store/utils.py b/rhodecode/apps/file_store/utils.py --- a/rhodecode/apps/file_store/utils.py +++ b/rhodecode/apps/file_store/utils.py @@ -19,9 +19,10 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ -import os import uuid +import pathlib2 + def get_file_storage(settings): from rhodecode.apps.file_store.local_store import LocalFileStorage @@ -30,6 +31,11 @@ def get_file_storage(settings): return LocalFileStorage(base_path=store_path) +def splitext(filename): + ext = ''.join(pathlib2.Path(filename).suffixes) + return filename, ext + + def uid_filename(filename, randomized=True): """ Generates a randomized or stable (uuid) filename, @@ -38,7 +44,8 @@ def uid_filename(filename, randomized=Tr :param filename: the original filename :param randomized: define if filename should be stable (sha1 based) or randomized """ - _, ext = os.path.splitext(filename) + + _, ext = splitext(filename) if randomized: uid = uuid.uuid4() else: diff --git a/rhodecode/apps/file_store/views.py b/rhodecode/apps/file_store/views.py --- a/rhodecode/apps/file_store/views.py +++ b/rhodecode/apps/file_store/views.py @@ -30,7 +30,7 @@ from rhodecode.apps.file_store.exception from rhodecode.lib import helpers as h from rhodecode.lib import audit_logger -from rhodecode.lib.auth import (CSRFRequired, NotAnonymous) +from rhodecode.lib.auth import (CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny) from rhodecode.model.db import Session, FileStore log = logging.getLogger(__name__) @@ -68,7 +68,7 @@ class FileStoreView(BaseAppView): 'user_id': self._rhodecode_user.user_id, 'ip': self._rhodecode_user.ip_addr}} try: - store_fid, metadata = self.storage.save_file( + store_uid, metadata = self.storage.save_file( file_obj.file, filename, extra_metadata=metadata) except FileNotAllowedException: return {'store_fid': None, @@ -82,7 +82,7 @@ class FileStoreView(BaseAppView): try: entry = FileStore.create( - file_uid=store_fid, filename=metadata["filename"], + file_uid=store_uid, filename=metadata["filename"], file_hash=metadata["sha256"], file_size=metadata["size"], file_description='upload attachment', check_acl=False, user_id=self._rhodecode_user.user_id @@ -96,8 +96,8 @@ class FileStoreView(BaseAppView): 'access_path': None, 'error': 'File {} failed to store in DB.'.format(filename)} - return {'store_fid': store_fid, - 'access_path': h.route_path('download_file', fid=store_fid)} + return {'store_fid': store_uid, + 'access_path': h.route_path('download_file', fid=store_uid)} @view_config(route_name='download_file') def download_file(self): @@ -109,6 +109,35 @@ class FileStoreView(BaseAppView): log.debug('File with FID:%s not found in the store', file_uid) raise HTTPNotFound() + db_obj = FileStore().query().filter(FileStore.file_uid == file_uid).scalar() + if not db_obj: + raise HTTPNotFound() + + # private upload for user + if db_obj.check_acl and db_obj.scope_user_id: + user = db_obj.user + if self._rhodecode_db_user.user_id != user.user_id: + log.warning('Access to file store object forbidden') + raise HTTPNotFound() + + # scoped to repository permissions + if db_obj.check_acl and db_obj.scope_repo_id: + repo = db_obj.repo + perm_set = ['repository.read', 'repository.write', 'repository.admin'] + has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'FileStore check') + if not has_perm: + log.warning('Access to file store object forbidden') + raise HTTPNotFound() + + # scoped to repository group permissions + if db_obj.check_acl and db_obj.scope_repo_group_id: + repo_group = db_obj.repo_group + perm_set = ['group.read', 'group.write', 'group.admin'] + has_perm = HasRepoGroupPermissionAny(*perm_set)(repo_group.group_name, 'FileStore check') + if not has_perm: + log.warning('Access to file store object forbidden') + raise HTTPNotFound() + FileStore.bump_access_counter(file_uid) file_path = self.storage.store_path(file_uid) diff --git a/rhodecode/apps/home/__init__.py b/rhodecode/apps/home/__init__.py --- a/rhodecode/apps/home/__init__.py +++ b/rhodecode/apps/home/__init__.py @@ -68,6 +68,10 @@ def includeme(config): pattern='/_markup_preview') config.add_route( + name='file_preview', + pattern='/_file_preview') + + config.add_route( name='store_user_session_value', pattern='/_store_session_attr') diff --git a/rhodecode/apps/home/views.py b/rhodecode/apps/home/views.py --- a/rhodecode/apps/home/views.py +++ b/rhodecode/apps/home/views.py @@ -27,11 +27,12 @@ from pyramid.view import view_config from rhodecode.apps._base import BaseAppView from rhodecode.lib import helpers as h from rhodecode.lib.auth import ( - LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, - CSRFRequired) + LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired) +from rhodecode.lib.codeblocks import filenode_as_lines_tokens from rhodecode.lib.index import searcher_from_config from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int from rhodecode.lib.ext_json import json +from rhodecode.lib.vcs.nodes import FileNode from rhodecode.model.db import ( func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup) from rhodecode.model.repo import RepoModel @@ -442,12 +443,14 @@ class HomeView(BaseAppView): def query_modifier(): qry = query return {'q': qry, 'type': 'content'} - label = u'File search for `{}` in this repository.'.format(query) + + label = u'File search for `{}`'.format(h.escape(query)) file_qry = { 'id': -10, 'value': query, 'value_display': label, 'type': 'search', + 'subtype': 'repo', 'url': h.route_path('search_repo', repo_name=repo_name, _query=query_modifier()) @@ -458,18 +461,19 @@ class HomeView(BaseAppView): qry = query return {'q': qry, 'type': 'commit'} - label = u'Commit search for `{}` in this repository.'.format(query) + label = u'Commit search for `{}`'.format(h.escape(query)) commit_qry = { 'id': -20, 'value': query, 'value_display': label, 'type': 'search', + 'subtype': 'repo', 'url': h.route_path('search_repo', repo_name=repo_name, _query=query_modifier()) } - if repo_context in ['commit', 'changelog']: + if repo_context in ['commit', 'commits']: queries.extend([commit_qry, file_qry]) elif repo_context in ['files', 'summary']: queries.extend([file_qry, commit_qry]) @@ -482,12 +486,13 @@ class HomeView(BaseAppView): qry = query return {'q': qry, 'type': 'content'} - label = u'File search for `{}` in this repository group'.format(query) + label = u'File search for `{}`'.format(query) file_qry = { 'id': -30, 'value': query, 'value_display': label, 'type': 'search', + 'subtype': 'repo_group', 'url': h.route_path('search_repo_group', repo_group_name=repo_group_name, _query=query_modifier()) @@ -498,18 +503,19 @@ class HomeView(BaseAppView): qry = query return {'q': qry, 'type': 'commit'} - label = u'Commit search for `{}` in this repository group'.format(query) + label = u'Commit search for `{}`'.format(query) commit_qry = { 'id': -40, 'value': query, 'value_display': label, 'type': 'search', + 'subtype': 'repo_group', 'url': h.route_path('search_repo_group', repo_group_name=repo_group_name, _query=query_modifier()) } - if repo_context in ['commit', 'changelog']: + if repo_context in ['commit', 'commits']: queries.extend([commit_qry, file_qry]) elif repo_context in ['files', 'summary']: queries.extend([file_qry, commit_qry]) @@ -524,6 +530,7 @@ class HomeView(BaseAppView): 'value': query, 'value_display': u'File search for: `{}`'.format(query), 'type': 'search', + 'subtype': 'global', 'url': h.route_path('search', _query={'q': query, 'type': 'content'}) }) @@ -533,6 +540,7 @@ class HomeView(BaseAppView): 'value': query, 'value_display': u'Commit search for: `{}`'.format(query), 'type': 'search', + 'subtype': 'global', 'url': h.route_path('search', _query={'q': query, 'type': 'commit'}) }) @@ -703,8 +711,11 @@ class HomeView(BaseAppView): def repo_group_main_page(self): c = self.load_default_context() c.repo_group = self.request.db_repo_group - repo_data, repo_group_data = self._get_groups_and_repos( - c.repo_group.group_id) + repo_data, repo_group_data = self._get_groups_and_repos(c.repo_group.group_id) + + # update every 5 min + if self.request.db_repo_group.last_commit_cache_update_diff > 60 * 5: + self.request.db_repo_group.update_commit_cache() # json used to render the grids c.repos_data = json.dumps(repo_data) @@ -733,6 +744,34 @@ class HomeView(BaseAppView): @LoginRequired() @CSRFRequired() @view_config( + route_name='file_preview', request_method='POST', + renderer='string', xhr=True) + def file_preview(self): + # Technically a CSRF token is not needed as no state changes with this + # call. However, as this is a POST is better to have it, so automated + # tools don't flag it as potential CSRF. + # Post is required because the payload could be bigger than the maximum + # allowed by GET. + + text = self.request.POST.get('text') + file_path = self.request.POST.get('file_path') + + renderer = h.renderer_from_filename(file_path) + + if renderer: + return h.render(text, renderer=renderer, mentions=True) + else: + self.load_default_context() + _render = self.request.get_partial_renderer( + 'rhodecode:templates/files/file_content.mako') + + lines = filenode_as_lines_tokens(FileNode(file_path, text)) + + return _render('render_lines', lines) + + @LoginRequired() + @CSRFRequired() + @view_config( route_name='store_user_session_value', request_method='POST', renderer='string', xhr=True) def store_user_session_attr(self): @@ -743,4 +782,4 @@ class HomeView(BaseAppView): if existing_value != val: self.request.session[key] = val - return 'stored:{}'.format(key) + return 'stored:{}:{}'.format(key, val) diff --git a/rhodecode/apps/journal/views.py b/rhodecode/apps/journal/views.py --- a/rhodecode/apps/journal/views.py +++ b/rhodecode/apps/journal/views.py @@ -31,12 +31,12 @@ from pyramid.renderers import render from rhodecode.apps._base import BaseAppView from rhodecode.model.db import ( - or_, joinedload, UserLog, UserFollowing, User, UserApiKeys) + or_, joinedload, Repository, UserLog, UserFollowing, User, UserApiKeys) from rhodecode.model.meta import Session import rhodecode.lib.helpers as h from rhodecode.lib.helpers import Page from rhodecode.lib.user_log_filter import user_log_filter -from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired +from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, HasRepoPermissionAny from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe from rhodecode.model.scm import ScmModel @@ -153,7 +153,7 @@ class JournalView(BaseAppView): desc = action_extra() _url = h.route_url('home') if entry.repository is not None: - _url = h.route_url('repo_changelog', + _url = h.route_url('repo_commits', repo_name=entry.repository.repo_name) feed.add_item( @@ -199,7 +199,7 @@ class JournalView(BaseAppView): desc = action_extra() _url = h.route_url('home') if entry.repository is not None: - _url = h.route_url('repo_changelog', + _url = h.route_url('repo_commits', repo_name=entry.repository.repo_name) feed.add_item( @@ -297,18 +297,19 @@ class JournalView(BaseAppView): user_id = self.request.POST.get('follows_user_id') if user_id: try: - ScmModel().toggle_following_user( - user_id, self._rhodecode_user.user_id) + ScmModel().toggle_following_user(user_id, self._rhodecode_user.user_id) Session().commit() return 'ok' except Exception: raise HTTPBadRequest() repo_id = self.request.POST.get('follows_repo_id') - if repo_id: + repo = Repository.get_or_404(repo_id) + perm_set = ['repository.read', 'repository.write', 'repository.admin'] + has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'RepoWatch check') + if repo and has_perm: try: - ScmModel().toggle_following_repo( - repo_id, self._rhodecode_user.user_id) + ScmModel().toggle_following_repo(repo_id, self._rhodecode_user.user_id) Session().commit() return 'ok' except Exception: diff --git a/rhodecode/apps/my_account/views/my_account.py b/rhodecode/apps/my_account/views/my_account.py --- a/rhodecode/apps/my_account/views/my_account.py +++ b/rhodecode/apps/my_account/views/my_account.py @@ -360,7 +360,7 @@ class MyAccountView(BaseAppView, DataGri 'repository.read', 'repository.write', 'repository.admin']) repos_data = RepoModel().get_repos_as_dict( - repo_list=repo_list, admin=admin) + repo_list=repo_list, admin=admin, short_name=False) # json used to render the grid return json.dumps(repos_data) @@ -423,7 +423,7 @@ class MyAccountView(BaseAppView, DataGri default_redirect_url = '' # save repo - if entry.get('bookmark_repo'): + if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')): repo = Repository.get(entry['bookmark_repo']) perm_check = HasRepoPermissionAny( 'repository.read', 'repository.write', 'repository.admin') @@ -432,7 +432,7 @@ class MyAccountView(BaseAppView, DataGri should_save = True default_redirect_url = '${repo_url}' # save repo group - elif entry.get('bookmark_repo_group'): + elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')): repo_group = RepoGroup.get(entry['bookmark_repo_group']) perm_check = HasRepoGroupPermissionAny( 'group.read', 'group.write', 'group.admin') diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py --- a/rhodecode/apps/repository/__init__.py +++ b/rhodecode/apps/repository/__init__.py @@ -90,7 +90,7 @@ def includeme(config): # Files config.add_route( name='repo_archivefile', - pattern='/{repo_name:.*?[^/]}/archive/{fname}', repo_route=True) + pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True) config.add_route( name='repo_files_diff', @@ -172,6 +172,10 @@ def includeme(config): pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}', repo_route=True) config.add_route( + name='repo_files_upload_file', + pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}', + repo_route=True) + config.add_route( name='repo_files_create_file', pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}', repo_route=True) @@ -189,19 +193,27 @@ def includeme(config): name='repo_stats', pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True) - # Changelog + # Commits + config.add_route( + name='repo_commits', + pattern='/{repo_name:.*?[^/]}/commits', repo_route=True) + config.add_route( + name='repo_commits_file', + pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True) + config.add_route( + name='repo_commits_elements', + pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True) + config.add_route( + name='repo_commits_elements_file', + pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True) + + # Changelog (old deprecated name for commits page) config.add_route( name='repo_changelog', pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True) config.add_route( name='repo_changelog_file', pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True) - config.add_route( - name='repo_changelog_elements', - pattern='/{repo_name:.*?[^/]}/changelog_elements', repo_route=True) - config.add_route( - name='repo_changelog_elements_file', - pattern='/{repo_name:.*?[^/]}/changelog_elements/{commit_id}/{f_path:.*}', repo_route=True) # Compare config.add_route( @@ -312,6 +324,11 @@ def includeme(config): pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete', repo_route=True, repo_accepted_types=['hg', 'git']) + # Artifacts, (EE feature) + config.add_route( + name='repo_artifacts_list', + pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True) + # Settings config.add_route( name='edit_repo', diff --git a/rhodecode/apps/repository/tests/test_pull_requests_list.py b/rhodecode/apps/repository/tests/test_pull_requests_list.py --- a/rhodecode/apps/repository/tests/test_pull_requests_list.py +++ b/rhodecode/apps/repository/tests/test_pull_requests_list.py @@ -40,11 +40,11 @@ def route_path(name, params=None, **kwar class TestPullRequestList(object): @pytest.mark.parametrize('params, expected_title', [ - ({'source': 0, 'closed': 1}, 'Closed Pull Requests'), - ({'source': 0, 'my': 1}, 'opened by me'), - ({'source': 0, 'awaiting_review': 1}, 'awaiting review'), - ({'source': 0, 'awaiting_my_review': 1}, 'awaiting my review'), - ({'source': 1}, 'Pull Requests from'), + ({'source': 0, 'closed': 1}, 'Closed'), + ({'source': 0, 'my': 1}, 'Opened by me'), + ({'source': 0, 'awaiting_review': 1}, 'Awaiting review'), + ({'source': 0, 'awaiting_my_review': 1}, 'Awaiting my review'), + ({'source': 1}, 'From this repo'), ]) def test_showing_list_page(self, backend, pr_util, params, expected_title): pull_request = pr_util.create_pull_request() @@ -55,9 +55,10 @@ class TestPullRequestList(object): params=params)) assert_response = response.assert_response() - assert_response.element_equals_to('.panel-title', expected_title) - element = assert_response.get_element('.panel-title') - element_text = assert_response._element_to_string(element) + + element = assert_response.get_element('.title .active') + element_text = element.text_content() + assert expected_title == element_text def test_showing_list_page_data(self, backend, pr_util, xhr_header): pull_request = pr_util.create_pull_request() diff --git a/rhodecode/apps/repository/tests/test_repo_changelog.py b/rhodecode/apps/repository/tests/test_repo_changelog.py --- a/rhodecode/apps/repository/tests/test_repo_changelog.py +++ b/rhodecode/apps/repository/tests/test_repo_changelog.py @@ -32,9 +32,10 @@ def route_path(name, params=None, **kwar import urllib base_url = { - 'repo_changelog':'/{repo_name}/changelog', - 'repo_changelog_file':'/{repo_name}/changelog/{commit_id}/{f_path}', - 'repo_changelog_elements':'/{repo_name}/changelog_elements', + 'repo_changelog': '/{repo_name}/changelog', + 'repo_commits': '/{repo_name}/commits', + 'repo_commits_file': '/{repo_name}/commits/{commit_id}/{f_path}', + 'repo_commits_elements': '/{repo_name}/commits_elements', }[name].format(**kwargs) if params: @@ -42,8 +43,22 @@ def route_path(name, params=None, **kwar return base_url +def assert_commits_on_page(response, indexes): + found_indexes = [int(idx) for idx in MATCH_HASH.findall(response.body)] + assert found_indexes == indexes + + class TestChangelogController(TestController): + def test_commits_page(self, backend): + self.log_user() + response = self.app.get( + route_path('repo_commits', repo_name=backend.repo_name)) + + first_idx = -1 + last_idx = -DEFAULT_CHANGELOG_SIZE + self.assert_commit_range_on_page(response, first_idx, last_idx, backend) + def test_changelog(self, backend): self.log_user() response = self.app.get( @@ -62,6 +77,14 @@ class TestChangelogController(TestContro params=dict(branch=backend.default_branch_name)), status=200) + @pytest.mark.backends("hg", "git") + def test_commits_filtered_by_branch(self, backend): + self.log_user() + self.app.get( + route_path('repo_commits', repo_name=backend.repo_name, + params=dict(branch=backend.default_branch_name)), + status=200) + @pytest.mark.backends("svn") def test_changelog_filtered_by_branch_svn(self, autologin_user, backend): repo = backend['svn-simple-layout'] @@ -70,27 +93,22 @@ class TestChangelogController(TestContro params=dict(branch='trunk')), status=200) - self.assert_commits_on_page( - response, indexes=[15, 12, 7, 3, 2, 1]) + assert_commits_on_page(response, indexes=[15, 12, 7, 3, 2, 1]) - def test_changelog_filtered_by_wrong_branch(self, backend): + def test_commits_filtered_by_wrong_branch(self, backend): self.log_user() branch = 'wrong-branch-name' response = self.app.get( - route_path('repo_changelog', repo_name=backend.repo_name, + route_path('repo_commits', repo_name=backend.repo_name, params=dict(branch=branch)), status=302) - expected_url = '/{repo}/changelog/{branch}'.format( + expected_url = '/{repo}/commits/{branch}'.format( repo=backend.repo_name, branch=branch) assert expected_url in response.location response = response.follow() expected_warning = 'Branch {} is not found.'.format(branch) assert expected_warning in response.body - def assert_commits_on_page(self, response, indexes): - found_indexes = [int(idx) for idx in MATCH_HASH.findall(response.body)] - assert found_indexes == indexes - @pytest.mark.xfail_backends("svn", reason="Depends on branch support") def test_changelog_filtered_by_branch_with_merges( self, autologin_user, backend): @@ -112,21 +130,20 @@ class TestChangelogController(TestContro status=200) @pytest.mark.backends("hg") - def test_changelog_closed_branches(self, autologin_user, backend): + def test_commits_closed_branches(self, autologin_user, backend): repo = backend['closed_branch'] response = self.app.get( - route_path('repo_changelog', repo_name=repo.repo_name, + route_path('repo_commits', repo_name=repo.repo_name, params=dict(branch='experimental')), status=200) - self.assert_commits_on_page( - response, indexes=[3, 1]) + assert_commits_on_page(response, indexes=[3, 1]) def test_changelog_pagination(self, backend): self.log_user() # pagination, walk up to page 6 changelog_url = route_path( - 'repo_changelog', repo_name=backend.repo_name) + 'repo_commits', repo_name=backend.repo_name) for page in range(1, 7): response = self.app.get(changelog_url, {'page': page}) @@ -138,22 +155,30 @@ class TestChangelogController(TestContro def assert_commit_range_on_page( self, response, first_idx, last_idx, backend): input_template = ( - """""" ) + commit_span_template = """r%s:%s""" repo = backend.repo first_commit_on_page = repo.get_commit(commit_idx=first_idx) response.mustcontain( - input_template % {'raw_id': first_commit_on_page.raw_id}) + input_template % {'raw_id': first_commit_on_page.raw_id, + 'idx': first_commit_on_page.idx, + 'short_id': first_commit_on_page.short_id}) + response.mustcontain(commit_span_template % ( first_commit_on_page.idx, first_commit_on_page.short_id) ) last_commit_on_page = repo.get_commit(commit_idx=last_idx) response.mustcontain( - input_template % {'raw_id': last_commit_on_page.raw_id}) + input_template % {'raw_id': last_commit_on_page.raw_id, + 'idx': last_commit_on_page.idx, + 'short_id': last_commit_on_page.short_id}) response.mustcontain(commit_span_template % ( last_commit_on_page.idx, last_commit_on_page.short_id) ) @@ -168,10 +193,10 @@ class TestChangelogController(TestContro '/vcs/exceptions.py', '//vcs/exceptions.py' ]) - def test_changelog_with_filenode(self, backend, test_path): + def test_commits_with_filenode(self, backend, test_path): self.log_user() response = self.app.get( - route_path('repo_changelog_file', repo_name=backend.repo_name, + route_path('repo_commits_file', repo_name=backend.repo_name, commit_id='tip', f_path=test_path), ) @@ -180,16 +205,16 @@ class TestChangelogController(TestContro response.mustcontain('Added not implemented hg backend test case') response.mustcontain('Added BaseChangeset class') - def test_changelog_with_filenode_that_is_dirnode(self, backend): + def test_commits_with_filenode_that_is_dirnode(self, backend): self.log_user() self.app.get( - route_path('repo_changelog_file', repo_name=backend.repo_name, + route_path('repo_commits_file', repo_name=backend.repo_name, commit_id='tip', f_path='/tests'), status=302) - def test_changelog_with_filenode_not_existing(self, backend): + def test_commits_with_filenode_not_existing(self, backend): self.log_user() self.app.get( - route_path('repo_changelog_file', repo_name=backend.repo_name, + route_path('repo_commits_file', repo_name=backend.repo_name, commit_id='tip', f_path='wrong_path'), status=302) diff --git a/rhodecode/apps/repository/tests/test_repo_compare.py b/rhodecode/apps/repository/tests/test_repo_compare.py --- a/rhodecode/apps/repository/tests/test_repo_compare.py +++ b/rhodecode/apps/repository/tests/test_repo_compare.py @@ -94,6 +94,7 @@ class TestCompareView(object): origin_repo = origin.scm_instance(cache=False) origin_repo.config.clear_section('hooks') origin_repo.pull(fork.repo_full_path, commit_ids=[commit3.raw_id]) + origin_repo = origin.scm_instance(cache=False) # cache rebuild # Verify test fixture setup # This does not work for git @@ -162,8 +163,7 @@ class TestCompareView(object): compare_page.target_source_are_disabled() @pytest.mark.xfail_backends("svn", reason="Depends on branch support") - def test_compare_forks_on_branch_extra_commits_origin_has_incomming( - self, backend): + def test_compare_forks_on_branch_extra_commits_origin_has_incomming(self, backend): repo1 = backend.create_repo() # commit something ! diff --git a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py --- a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py +++ b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py @@ -21,6 +21,7 @@ import pytest from rhodecode.lib.vcs import nodes +from rhodecode.lib.vcs.backends.base import EmptyCommit from rhodecode.tests.fixture import Fixture from rhodecode.tests.utils import commit_change @@ -43,70 +44,7 @@ def route_path(name, params=None, **kwar @pytest.mark.usefixtures("autologin_user", "app") class TestSideBySideDiff(object): - def test_diff_side_by_side(self, app, backend, backend_stub): - f_path = 'test_sidebyside_file.py' - commit1_content = 'content-25d7e49c18b159446c\n' - commit2_content = 'content-603d6c72c46d953420\n' - repo = backend.create_repo() - - commit1 = commit_change( - repo.repo_name, filename=f_path, content=commit1_content, - message='A', vcs_type=backend.alias, parent=None, newfile=True) - - commit2 = commit_change( - repo.repo_name, filename=f_path, content=commit2_content, - message='B, child of A', vcs_type=backend.alias, parent=commit1) - - response = self.app.get(route_path( - 'repo_compare', - repo_name=repo.repo_name, - source_ref_type='rev', - source_ref=commit1.raw_id, - target_ref_type='rev', - target_ref=commit2.raw_id, - params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside') - )) - - response.mustcontain('Expand 1 commit') - response.mustcontain('1 file changed') - - response.mustcontain( - 'r%s:%s...r%s:%s' % ( - commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) - - response.mustcontain('{}'.format(f_path)) - - def test_diff_side_by_side_with_empty_file(self, app, backend, backend_stub): - commits = [ - {'message': 'First commit'}, - {'message': 'Commit with binary', - 'added': [nodes.FileNode('file.empty', content='')]}, - ] - f_path = 'file.empty' - repo = backend.create_repo(commits=commits) - commit1 = repo.get_commit(commit_idx=0) - commit2 = repo.get_commit(commit_idx=1) - - response = self.app.get(route_path( - 'repo_compare', - repo_name=repo.repo_name, - source_ref_type='rev', - source_ref=commit1.raw_id, - target_ref_type='rev', - target_ref=commit2.raw_id, - params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside') - )) - - response.mustcontain('Expand 1 commit') - response.mustcontain('1 file changed') - - response.mustcontain( - 'r%s:%s...r%s:%s' % ( - commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) - - response.mustcontain('{}'.format(f_path)) - - def test_diff_sidebyside_two_commits(self, app, backend): + def test_diff_sidebyside_single_commit(self, app, backend): commit_id_range = { 'hg': { 'commits': ['25d7e49c18b159446cadfa506a5cf8ad1cb04067', @@ -141,26 +79,164 @@ class TestSideBySideDiff(object): params=dict(target_repo=backend.repo_name, diffmode='sidebyside') )) + response.mustcontain(file_changes) response.mustcontain('Expand 1 commit') - response.mustcontain(file_changes) - def test_diff_sidebyside_two_commits_single_file(self, app, backend): + def test_diff_sidebyside_two_commits(self, app, backend): commit_id_range = { 'hg': { - 'commits': ['25d7e49c18b159446cadfa506a5cf8ad1cb04067', + 'commits': ['4fdd71e9427417b2e904e0464c634fdee85ec5a7', '603d6c72c46d953420c89d36372f08d9f305f5dd'], - 'changes': '1 file changed: 1 inserted, 1 deleted' + 'changes': '32 files changed: 1165 inserted, 308 deleted' }, 'git': { - 'commits': ['6fc9270775aaf5544c1deb014f4ddd60c952fcbb', + 'commits': ['f5fbf9cfd5f1f1be146f6d3b38bcd791a7480c13', '03fa803d7e9fb14daa9a3089e0d1494eda75d986'], - 'changes': '1 file changed: 1 inserted, 1 deleted' + 'changes': '32 files changed: 1165 inserted, 308 deleted' }, 'svn': { - 'commits': ['336', + 'commits': ['335', '337'], - 'changes': '1 file changed: 1 inserted, 1 deleted' + 'changes': '32 files changed: 1179 inserted, 310 deleted' + }, + } + + commit_info = commit_id_range[backend.alias] + commit2, commit1 = commit_info['commits'] + file_changes = commit_info['changes'] + + response = self.app.get(route_path( + 'repo_compare', + repo_name=backend.repo_name, + source_ref_type='rev', + source_ref=commit2, + target_repo=backend.repo_name, + target_ref_type='rev', + target_ref=commit1, + params=dict(target_repo=backend.repo_name, diffmode='sidebyside') + )) + + response.mustcontain(file_changes) + response.mustcontain('Expand 2 commits') + + @pytest.mark.xfail(reason='GIT does not handle empty commit compare correct (missing 1 commit)') + def test_diff_side_by_side_from_0_commit(self, app, backend, backend_stub): + f_path = 'test_sidebyside_file.py' + commit1_content = 'content-25d7e49c18b159446c\n' + commit2_content = 'content-603d6c72c46d953420\n' + repo = backend.create_repo() + + commit1 = commit_change( + repo.repo_name, filename=f_path, content=commit1_content, + message='A', vcs_type=backend.alias, parent=None, newfile=True) + + commit2 = commit_change( + repo.repo_name, filename=f_path, content=commit2_content, + message='B, child of A', vcs_type=backend.alias, parent=commit1) + + response = self.app.get(route_path( + 'repo_compare', + repo_name=repo.repo_name, + source_ref_type='rev', + source_ref=EmptyCommit().raw_id, + target_ref_type='rev', + target_ref=commit2.raw_id, + params=dict(diffmode='sidebyside') + )) + + response.mustcontain('Expand 2 commits') + response.mustcontain('123 file changed') + + response.mustcontain( + 'r%s:%s...r%s:%s' % ( + commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) + + response.mustcontain('{}'.format(f_path)) + + @pytest.mark.xfail(reason='GIT does not handle empty commit compare correct (missing 1 commit)') + def test_diff_side_by_side_from_0_commit_with_file_filter(self, app, backend, backend_stub): + f_path = 'test_sidebyside_file.py' + commit1_content = 'content-25d7e49c18b159446c\n' + commit2_content = 'content-603d6c72c46d953420\n' + repo = backend.create_repo() + + commit1 = commit_change( + repo.repo_name, filename=f_path, content=commit1_content, + message='A', vcs_type=backend.alias, parent=None, newfile=True) + + commit2 = commit_change( + repo.repo_name, filename=f_path, content=commit2_content, + message='B, child of A', vcs_type=backend.alias, parent=commit1) + + response = self.app.get(route_path( + 'repo_compare', + repo_name=repo.repo_name, + source_ref_type='rev', + source_ref=EmptyCommit().raw_id, + target_ref_type='rev', + target_ref=commit2.raw_id, + params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside') + )) + + response.mustcontain('Expand 2 commits') + response.mustcontain('1 file changed') + + response.mustcontain( + 'r%s:%s...r%s:%s' % ( + commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) + + response.mustcontain('{}'.format(f_path)) + + def test_diff_side_by_side_with_empty_file(self, app, backend, backend_stub): + commits = [ + {'message': 'First commit'}, + {'message': 'Second commit'}, + {'message': 'Commit with binary', + 'added': [nodes.FileNode('file.empty', content='')]}, + ] + f_path = 'file.empty' + repo = backend.create_repo(commits=commits) + commit1 = repo.get_commit(commit_idx=0) + commit2 = repo.get_commit(commit_idx=1) + commit3 = repo.get_commit(commit_idx=2) + + response = self.app.get(route_path( + 'repo_compare', + repo_name=repo.repo_name, + source_ref_type='rev', + source_ref=commit1.raw_id, + target_ref_type='rev', + target_ref=commit3.raw_id, + params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside') + )) + + response.mustcontain('Expand 2 commits') + response.mustcontain('1 file changed') + + response.mustcontain( + 'r%s:%s...r%s:%s' % ( + commit2.idx, commit2.short_id, commit3.idx, commit3.short_id)) + + response.mustcontain('{}'.format(f_path)) + + def test_diff_sidebyside_two_commits_with_file_filter(self, app, backend): + commit_id_range = { + 'hg': { + 'commits': ['4fdd71e9427417b2e904e0464c634fdee85ec5a7', + '603d6c72c46d953420c89d36372f08d9f305f5dd'], + 'changes': '1 file changed: 3 inserted, 3 deleted' + }, + 'git': { + 'commits': ['f5fbf9cfd5f1f1be146f6d3b38bcd791a7480c13', + '03fa803d7e9fb14daa9a3089e0d1494eda75d986'], + 'changes': '1 file changed: 3 inserted, 3 deleted' + }, + + 'svn': { + 'commits': ['335', + '337'], + 'changes': '1 file changed: 3 inserted, 3 deleted' }, } f_path = 'docs/conf.py' @@ -179,5 +255,5 @@ class TestSideBySideDiff(object): params=dict(f_path=f_path, target_repo=backend.repo_name, diffmode='sidebyside') )) - response.mustcontain('Expand 1 commit') + response.mustcontain('Expand 2 commits') response.mustcontain(file_changes) diff --git a/rhodecode/apps/repository/tests/test_repo_files.py b/rhodecode/apps/repository/tests/test_repo_files.py --- a/rhodecode/apps/repository/tests/test_repo_files.py +++ b/rhodecode/apps/repository/tests/test_repo_files.py @@ -243,7 +243,7 @@ class TestFilesViews(object): repo_name=backend.repo_name, commit_id=commit.raw_id, f_path='vcs/nodes.py')) - msgbox = """
%s
""" + msgbox = """
%s
""" response.mustcontain(msgbox % (commit.message, )) assert_response = response.assert_response() @@ -313,6 +313,7 @@ class TestFilesViews(object): expected_data = json.loads( fixture.load_resource('svn_node_history_branches.json')) + assert expected_data == response.json def test_file_source_history_with_annotation(self, backend, xhr_header): @@ -521,10 +522,10 @@ class TestRepositoryArchival(object): def test_archival(self, backend): backend.enable_downloads() commit = backend.repo.get_commit(commit_idx=173) - for archive, info in settings.ARCHIVE_SPECS.items(): - mime_type, arch_ext = info - short = commit.short_id + arch_ext - fname = commit.raw_id + arch_ext + for a_type, content_type, extension in settings.ARCHIVE_SPECS: + + short = commit.short_id + extension + fname = commit.raw_id + extension filename = '%s-%s' % (backend.repo_name, short) response = self.app.get( route_path('repo_archivefile', @@ -534,7 +535,7 @@ class TestRepositoryArchival(object): assert response.status == '200 OK' headers = [ ('Content-Disposition', 'attachment; filename=%s' % filename), - ('Content-Type', '%s' % mime_type), + ('Content-Type', '%s' % content_type), ] for header in headers: @@ -761,7 +762,7 @@ class TestModifyFilesWithWebInterface(ob @pytest.mark.xfail_backends("svn", reason="Depends on online editing") def test_add_file_into_repo_missing_content(self, backend, csrf_token): - repo = backend.create_repo() + backend.create_repo() filename = 'init.py' response = self.app.post( route_path('repo_files_create_file', @@ -770,26 +771,25 @@ class TestModifyFilesWithWebInterface(ob params={ 'content': "", 'filename': filename, - 'location': "", 'csrf_token': csrf_token, }, status=302) - assert_session_flash(response, - 'Successfully committed new file `{}`'.format( - os.path.join(filename))) + expected_msg = 'Successfully committed new file `{}`'.format(os.path.join(filename)) + assert_session_flash(response, expected_msg) def test_add_file_into_repo_missing_filename(self, backend, csrf_token): + commit_id = backend.repo.get_commit().raw_id response = self.app.post( route_path('repo_files_create_file', repo_name=backend.repo_name, - commit_id='tip', f_path='/'), + commit_id=commit_id, f_path='/'), params={ 'content': "foo", 'csrf_token': csrf_token, }, status=302) - assert_session_flash(response, 'No filename') + assert_session_flash(response, 'No filename specified') def test_add_file_into_repo_errors_and_no_commits( self, backend, csrf_token): @@ -806,7 +806,7 @@ class TestModifyFilesWithWebInterface(ob }, status=302) - assert_session_flash(response, 'No filename') + assert_session_flash(response, 'No filename specified') # Not allowed, redirect to the summary redirected = response.follow() @@ -817,52 +817,51 @@ class TestModifyFilesWithWebInterface(ob assert redirected.request.path == summary_url - @pytest.mark.parametrize("location, filename", [ - ('/abs', 'foo'), - ('../rel', 'foo'), - ('file/../foo', 'foo'), + @pytest.mark.parametrize("filename, clean_filename", [ + ('/abs/foo', 'abs/foo'), + ('../rel/foo', 'rel/foo'), + ('file/../foo/foo', 'file/foo/foo'), ]) - def test_add_file_into_repo_bad_filenames( - self, location, filename, backend, csrf_token): + def test_add_file_into_repo_bad_filenames(self, filename, clean_filename, backend, csrf_token): + repo = backend.create_repo() + commit_id = repo.get_commit().raw_id + response = self.app.post( route_path('repo_files_create_file', - repo_name=backend.repo_name, - commit_id='tip', f_path='/'), + repo_name=repo.repo_name, + commit_id=commit_id, f_path='/'), params={ 'content': "foo", 'filename': filename, - 'location': location, 'csrf_token': csrf_token, }, status=302) - assert_session_flash( - response, - 'The location specified must be a relative path and must not ' - 'contain .. in the path') + expected_msg = 'Successfully committed new file `{}`'.format(clean_filename) + assert_session_flash(response, expected_msg) - @pytest.mark.parametrize("cnt, location, filename", [ - (1, '', 'foo.txt'), - (2, 'dir', 'foo.rst'), - (3, 'rel/dir', 'foo.bar'), + @pytest.mark.parametrize("cnt, filename, content", [ + (1, 'foo.txt', "Content"), + (2, 'dir/foo.rst', "Content"), + (3, 'dir/foo-second.rst', "Content"), + (4, 'rel/dir/foo.bar', "Content"), ]) - def test_add_file_into_repo(self, cnt, location, filename, backend, - csrf_token): + def test_add_file_into_empty_repo(self, cnt, filename, content, backend, csrf_token): repo = backend.create_repo() + commit_id = repo.get_commit().raw_id response = self.app.post( route_path('repo_files_create_file', repo_name=repo.repo_name, - commit_id='tip', f_path='/'), + commit_id=commit_id, f_path='/'), params={ - 'content': "foo", + 'content': content, 'filename': filename, - 'location': location, 'csrf_token': csrf_token, }, status=302) - assert_session_flash(response, - 'Successfully committed new file `{}`'.format( - os.path.join(location, filename))) + + expected_msg = 'Successfully committed new file `{}`'.format(filename) + assert_session_flash(response, expected_msg) def test_edit_file_view(self, backend): response = self.app.get( @@ -884,8 +883,7 @@ class TestModifyFilesWithWebInterface(ob f_path='vcs/nodes.py'), status=302) assert_session_flash( - response, - 'You can only edit files with commit being a valid branch') + response, 'Cannot modify file. Given commit `tip` is not head of a branch.') def test_edit_file_view_commit_changes(self, backend, csrf_token): repo = backend.create_repo() @@ -953,8 +951,7 @@ class TestModifyFilesWithWebInterface(ob f_path='vcs/nodes.py'), status=302) assert_session_flash( - response, - 'You can only delete files with commit being a valid branch') + response, 'Cannot modify file. Given commit `tip` is not head of a branch.') def test_delete_file_view_commit_changes(self, backend, csrf_token): repo = backend.create_repo() @@ -992,7 +989,7 @@ class TestFilesViewOtherCases(object): repo_file_add_url = route_path( 'repo_files_add_file', repo_name=repo.repo_name, - commit_id=0, f_path='') + '#edit' + commit_id=0, f_path='') assert_session_flash( response, @@ -1009,7 +1006,7 @@ class TestFilesViewOtherCases(object): repo_file_add_url = route_path( 'repo_files_add_file', repo_name=repo.repo_name, - commit_id=0, f_path='') + '#edit' + commit_id=0, f_path='') response = self.app.get( route_path('repo_files', diff --git a/rhodecode/apps/repository/tests/test_repo_pullrequests.py b/rhodecode/apps/repository/tests/test_repo_pullrequests.py --- a/rhodecode/apps/repository/tests/test_repo_pullrequests.py +++ b/rhodecode/apps/repository/tests/test_repo_pullrequests.py @@ -40,6 +40,8 @@ def route_path(name, params=None, **kwar base_url = { 'repo_changelog': '/{repo_name}/changelog', 'repo_changelog_file': '/{repo_name}/changelog/{commit_id}/{f_path}', + 'repo_commits': '/{repo_name}/commits', + 'repo_commits_file': '/{repo_name}/commits/{commit_id}/{f_path}', 'pullrequest_show': '/{repo_name}/pull-request/{pull_request_id}', 'pullrequest_show_all': '/{repo_name}/pull-request', 'pullrequest_show_all_data': '/{repo_name}/pull-request-data', @@ -998,11 +1000,11 @@ class TestPullrequestsView(object): assert len(target_children) == 1 expected_origin_link = route_path( - 'repo_changelog', + 'repo_commits', repo_name=pull_request.source_repo.scm_instance().name, params=dict(branch='origin')) expected_target_link = route_path( - 'repo_changelog', + 'repo_commits', repo_name=pull_request.target_repo.scm_instance().name, params=dict(branch='target')) assert origin_children[0].attrib['href'] == expected_origin_link diff --git a/rhodecode/apps/repository/tests/test_repo_summary.py b/rhodecode/apps/repository/tests/test_repo_summary.py --- a/rhodecode/apps/repository/tests/test_repo_summary.py +++ b/rhodecode/apps/repository/tests/test_repo_summary.py @@ -350,11 +350,11 @@ class TestCreateReferenceData(object): { 'children': [ { - 'id': 'a', 'raw_id': 'a_id', 'text': 'a', 'type': 't1', + 'id': 'a', 'idx': 0, 'raw_id': 'a_id', 'text': 'a', 'type': 't1', 'files_url': expected_files_url + 'a/?at=a', }, { - 'id': 'b', 'raw_id': 'b_id', 'text': 'b', 'type': 't1', + 'id': 'b', 'idx': 0, 'raw_id': 'b_id', 'text': 'b', 'type': 't1', 'files_url': expected_files_url + 'b/?at=b', } ], @@ -363,7 +363,7 @@ class TestCreateReferenceData(object): { 'children': [ { - 'id': 'c', 'raw_id': 'c_id', 'text': 'c', 'type': 't2', + 'id': 'c', 'idx': 0, 'raw_id': 'c_id', 'text': 'c', 'type': 't2', 'files_url': expected_files_url + 'c/?at=c', } ], @@ -385,12 +385,12 @@ class TestCreateReferenceData(object): { 'children': [ { - 'id': 'a@a_id', 'raw_id': 'a_id', + 'id': 'a@a_id', 'idx': 0, 'raw_id': 'a_id', 'text': 'a', 'type': 't1', 'files_url': expected_files_url + 'a_id/a?at=a', }, { - 'id': 'b@b_id', 'raw_id': 'b_id', + 'id': 'b@b_id', 'idx': 0, 'raw_id': 'b_id', 'text': 'b', 'type': 't1', 'files_url': expected_files_url + 'b_id/b?at=b', } @@ -400,7 +400,7 @@ class TestCreateReferenceData(object): { 'children': [ { - 'id': 'c@c_id', 'raw_id': 'c_id', + 'id': 'c@c_id', 'idx': 0, 'raw_id': 'c_id', 'text': 'c', 'type': 't2', 'files_url': expected_files_url + 'c_id/c?at=c', } @@ -516,6 +516,7 @@ class TestReferenceItems(object): 'text': ref_name, 'id': self._format_function(ref_name, ref_id), 'raw_id': ref_id, + 'idx': 0, 'type': self.ref_type, 'files_url': self.fake_url } diff --git a/rhodecode/apps/repository/views/repo_artifacts.py b/rhodecode/apps/repository/views/repo_artifacts.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/repository/views/repo_artifacts.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2011-2019 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging + +from pyramid.view import view_config + +from rhodecode.apps._base import RepoAppView +from rhodecode.lib.auth import ( + LoginRequired, HasRepoPermissionAnyDecorator) + +log = logging.getLogger(__name__) + + +class RepoArtifactsView(RepoAppView): + + def load_default_context(self): + c = self._get_local_tmpl_context(include_app_defaults=True) + c.rhodecode_repo = self.rhodecode_vcs_repo + return c + + @LoginRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + @view_config( + route_name='repo_artifacts_list', request_method='GET', + renderer='rhodecode:templates/artifacts/artifact_list.mako') + def repo_artifacts(self): + c = self.load_default_context() + c.active = 'artifacts' + return self._get_template_context(c) diff --git a/rhodecode/apps/repository/views/repo_changelog.py b/rhodecode/apps/repository/views/repo_changelog.py --- a/rhodecode/apps/repository/views/repo_changelog.py +++ b/rhodecode/apps/repository/views/repo_changelog.py @@ -113,7 +113,7 @@ class RepoChangelogView(RepoAppView): h.flash('Branch {} is not found.'.format(h.escape(branch_name)), category='warning') redirect_url = h.route_path( - 'repo_changelog_file', repo_name=repo_name, + 'repo_commits_file', repo_name=repo_name, commit_id=branch_name, f_path=f_path or '') raise HTTPFound(redirect_url) @@ -127,13 +127,13 @@ class RepoChangelogView(RepoAppView): if f_path: # changelog for file return h.route_path( - 'repo_changelog_file', + 'repo_commits_file', repo_name=c.rhodecode_db_repo.repo_name, commit_id=commit_id, f_path=f_path, _query=query_params) else: return h.route_path( - 'repo_changelog', + 'repo_commits', repo_name=c.rhodecode_db_repo.repo_name, _query=query_params) c.total_cs = len(collection) @@ -171,11 +171,18 @@ class RepoChangelogView(RepoAppView): @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') @view_config( + route_name='repo_commits', request_method='GET', + renderer='rhodecode:templates/commits/changelog.mako') + @view_config( + route_name='repo_commits_file', request_method='GET', + renderer='rhodecode:templates/commits/changelog.mako') + # old routes for backward compat + @view_config( route_name='repo_changelog', request_method='GET', - renderer='rhodecode:templates/changelog/changelog.mako') + renderer='rhodecode:templates/commits/changelog.mako') @view_config( route_name='repo_changelog_file', request_method='GET', - renderer='rhodecode:templates/changelog/changelog.mako') + renderer='rhodecode:templates/commits/changelog.mako') def repo_changelog(self): c = self.load_default_context() @@ -224,7 +231,7 @@ class RepoChangelogView(RepoAppView): except RepositoryError as e: h.flash(safe_str(e), category='warning') redirect_url = h.route_path( - 'repo_changelog', repo_name=self.db_repo_name) + 'repo_commits', repo_name=self.db_repo_name) raise HTTPFound(redirect_url) collection = list(reversed(collection)) else: @@ -246,14 +253,14 @@ class RepoChangelogView(RepoAppView): log.exception(safe_str(e)) h.flash(safe_str(h.escape(e)), category='error') raise HTTPFound( - h.route_path('repo_changelog', repo_name=self.db_repo_name)) + h.route_path('repo_commits', repo_name=self.db_repo_name)) if partial_xhr or self.request.environ.get('HTTP_X_PJAX'): # case when loading dynamic file history in file view # loading from ajax, we don't want the first result, it's popped # in the code above html = render( - 'rhodecode:templates/changelog/changelog_file_history.mako', + 'rhodecode:templates/commits/changelog_file_history.mako', self._get_template_context(c), self.request) return Response(html) @@ -271,14 +278,14 @@ class RepoChangelogView(RepoAppView): @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') @view_config( - route_name='repo_changelog_elements', request_method=('GET', 'POST'), - renderer='rhodecode:templates/changelog/changelog_elements.mako', + route_name='repo_commits_elements', request_method=('GET', 'POST'), + renderer='rhodecode:templates/commits/changelog_elements.mako', xhr=True) @view_config( - route_name='repo_changelog_elements_file', request_method=('GET', 'POST'), - renderer='rhodecode:templates/changelog/changelog_elements.mako', + route_name='repo_commits_elements_file', request_method=('GET', 'POST'), + renderer='rhodecode:templates/commits/changelog_elements.mako', xhr=True) - def repo_changelog_elements(self): + def repo_commits_elements(self): c = self.load_default_context() commit_id = self.request.matchdict.get('commit_id') f_path = self._get_f_path(self.request.matchdict) @@ -312,7 +319,7 @@ class RepoChangelogView(RepoAppView): except (RepositoryError, CommitDoesNotExistError, Exception) as e: log.exception(safe_str(e)) raise HTTPFound( - h.route_path('repo_changelog', repo_name=self.db_repo_name)) + h.route_path('repo_commits', repo_name=self.db_repo_name)) collection = base_commit.get_path_history( f_path, limit=hist_limit, pre_load=pre_load) diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -105,10 +105,9 @@ class RepoCommitsView(RepoAppView): c.commit_ranges = commits if not c.commit_ranges: - raise RepositoryError( - 'The commit range returned an empty result') - except CommitDoesNotExistError: - msg = _('No such commit exists for this repository') + raise RepositoryError('The commit range returned an empty result') + except CommitDoesNotExistError as e: + msg = _('No such commit exists. Org exception: `{}`').format(e) h.flash(msg, category='error') raise HTTPNotFound() except Exception: diff --git a/rhodecode/apps/repository/views/repo_compare.py b/rhodecode/apps/repository/views/repo_compare.py --- a/rhodecode/apps/repository/views/repo_compare.py +++ b/rhodecode/apps/repository/views/repo_compare.py @@ -214,29 +214,23 @@ class RepoCompareView(RepoAppView): pre_load = ["author", "branch", "date", "message"] c.ancestor = None - if c.file_path: - if source_commit == target_commit: - c.commit_ranges = [] - else: - c.commit_ranges = [target_commit] - else: - try: - c.commit_ranges = source_scm.compare( - source_commit.raw_id, target_commit.raw_id, - target_scm, merge, pre_load=pre_load) - if merge: - c.ancestor = source_scm.get_common_ancestor( - source_commit.raw_id, target_commit.raw_id, target_scm) - except RepositoryRequirementError: - msg = _('Could not compare repos with different ' - 'large file settings') - log.error(msg) - if partial: - return Response(msg) - h.flash(msg, category='error') - raise HTTPFound( - h.route_path('repo_compare_select', - repo_name=self.db_repo_name)) + try: + c.commit_ranges = source_scm.compare( + source_commit.raw_id, target_commit.raw_id, + target_scm, merge, pre_load=pre_load) or [] + if merge: + c.ancestor = source_scm.get_common_ancestor( + source_commit.raw_id, target_commit.raw_id, target_scm) + except RepositoryRequirementError: + msg = _('Could not compare repos with different ' + 'large file settings') + log.error(msg) + if partial: + return Response(msg) + h.flash(msg, category='error') + raise HTTPFound( + h.route_path('repo_compare_select', + repo_name=self.db_repo_name)) c.statuses = self.db_repo.statuses( [x.raw_id for x in c.commit_ranges]) diff --git a/rhodecode/apps/repository/views/repo_files.py b/rhodecode/apps/repository/views/repo_files.py --- a/rhodecode/apps/repository/views/repo_files.py +++ b/rhodecode/apps/repository/views/repo_files.py @@ -25,6 +25,7 @@ import shutil import tempfile import collections import urllib +import pathlib2 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound from pyramid.view import view_config @@ -42,7 +43,7 @@ from rhodecode.lib.exceptions import Non from rhodecode.lib.codeblocks import ( filenode_as_lines_tokens, filenode_as_annotated_lines_tokens) from rhodecode.lib.utils2 import ( - convert_line_endings, detect_mode, safe_str, str2bool, safe_int) + convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode) from rhodecode.lib.auth import ( LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) from rhodecode.lib.vcs import path as vcspath @@ -87,7 +88,7 @@ class RepoFilesView(RepoAppView): c.enable_downloads = self.db_repo.enable_downloads return c - def _ensure_not_locked(self): + def _ensure_not_locked(self, commit_id='tip'): _ = self.request.translate repo = self.db_repo @@ -98,21 +99,41 @@ class RepoFilesView(RepoAppView): 'warning') files_url = h.route_path( 'repo_files:default_path', - repo_name=self.db_repo_name, commit_id='tip') + repo_name=self.db_repo_name, commit_id=commit_id) raise HTTPFound(files_url) - def check_branch_permission(self, branch_name): + def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False): + _ = self.request.translate + + if not is_head: + message = _('Cannot modify file. ' + 'Given commit `{}` is not head of a branch.').format(commit_id) + h.flash(message, category='warning') + + if json_mode: + return message + + files_url = h.route_path( + 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id, + f_path=f_path) + raise HTTPFound(files_url) + + def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False): _ = self.request.translate rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission( self.db_repo_name, branch_name) if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']: - h.flash( - _('Branch `{}` changes forbidden by rule {}.').format(branch_name, rule), - 'warning') + message = _('Branch `{}` changes forbidden by rule {}.').format( + branch_name, rule) + h.flash(message, 'warning') + + if json_mode: + return message + files_url = h.route_path( - 'repo_files:default_path', - repo_name=self.db_repo_name, commit_id='tip') + 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id) + raise HTTPFound(files_url) def _get_commit_and_path(self): @@ -146,8 +167,7 @@ class RepoFilesView(RepoAppView): _url = h.route_path( 'repo_files_add_file', - repo_name=self.db_repo_name, commit_id=0, f_path='', - _anchor='edit') + repo_name=self.db_repo_name, commit_id=0, f_path='') if h.HasRepoPermissionAny( 'repository.write', 'repository.admin')(self.db_repo_name): @@ -185,8 +205,7 @@ class RepoFilesView(RepoAppView): h.flash(_('No such commit exists for this repository'), category='error') raise HTTPNotFound() except RepositoryError as e: - log.warning('Repository error while fetching ' - 'filenode `%s`. Err:%s', path, e) + log.warning('Repository error while fetching filenode `%s`. Err:%s', path, e) h.flash(safe_str(h.escape(e)), category='error') raise HTTPNotFound() @@ -195,12 +214,7 @@ class RepoFilesView(RepoAppView): def _is_valid_head(self, commit_id, repo): branch_name = sha_commit_id = '' is_head = False - - if h.is_svn(repo) and not repo.is_empty(): - # Note: Subversion only has one head. - if commit_id == repo.get_commit(commit_idx=-1).raw_id: - is_head = True - return branch_name, sha_commit_id, is_head + log.debug('Checking if commit_id `%s` is a head for %s.', commit_id, repo) for _branch_name, branch_commit_id in repo.branches.items(): # simple case we pass in branch name, it's a HEAD @@ -216,8 +230,14 @@ class RepoFilesView(RepoAppView): sha_commit_id = branch_commit_id break + if h.is_svn(repo) and not repo.is_empty(): + # Note: Subversion only has one head. + if commit_id == repo.get_commit(commit_idx=-1).raw_id: + is_head = True + return branch_name, sha_commit_id, is_head + # checked branches, means we only need to try to get the branch/commit_sha - if not repo.is_empty: + if not repo.is_empty(): commit = repo.get_commit(commit_id=commit_id) if commit: branch_name = commit.branch @@ -225,8 +245,7 @@ class RepoFilesView(RepoAppView): return branch_name, sha_commit_id, is_head - def _get_tree_at_commit( - self, c, commit_id, f_path, full_load=False): + def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False): repo_id = self.db_repo.repo_id force_recache = self.get_recache_flag() @@ -244,16 +263,16 @@ class RepoFilesView(RepoAppView): @region.conditional_cache_on_arguments(namespace=cache_namespace_uid, condition=cache_on) - def compute_file_tree(repo_id, commit_id, f_path, full_load): - log.debug('Generating cached file tree for repo_id: %s, %s, %s', - repo_id, commit_id, f_path) + def compute_file_tree(ver, repo_id, commit_id, f_path, full_load): + log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s', + ver, repo_id, commit_id, f_path) c.full_load = full_load return render( 'rhodecode:templates/files/files_browser_tree.mako', self._get_template_context(c), self.request) - return compute_file_tree(self.db_repo.repo_id, commit_id, f_path, full_load) + return compute_file_tree('v1', self.db_repo.repo_id, commit_id, f_path, full_load) def _get_archive_spec(self, fname): log.debug('Detecting archive spec for: `%s`', fname) @@ -261,8 +280,7 @@ class RepoFilesView(RepoAppView): fileformat = None ext = None content_type = None - for a_type, ext_data in settings.ARCHIVE_SPECS.items(): - content_type, extension = ext_data + for a_type, content_type, extension in settings.ARCHIVE_SPECS: if fname.endswith(extension): fileformat = a_type @@ -278,6 +296,15 @@ class RepoFilesView(RepoAppView): return commit_id, ext, fileformat, content_type + def create_pure_path(self, *parts): + # Split paths and sanitize them, removing any ../ etc + sanitized_path = [ + x for x in pathlib2.PurePath(*parts).parts + if x not in ['.', '..']] + + pure_path = pathlib2.PurePath(*sanitized_path) + return pure_path + @LoginRequired() @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') @@ -289,9 +316,10 @@ class RepoFilesView(RepoAppView): from rhodecode import CONFIG _ = self.request.translate self.load_default_context() - + default_at_path = '/' fname = self.request.matchdict['fname'] subrepos = self.request.GET.get('subrepos') == 'true' + at_path = self.request.GET.get('at_path') or default_at_path if not self.db_repo.enable_downloads: return Response(_('Downloads disabled')) @@ -311,10 +339,31 @@ class RepoFilesView(RepoAppView): except EmptyRepositoryError: return Response(_('Empty repository')) - archive_name = '%s-%s%s%s' % ( - safe_str(self.db_repo_name.replace('/', '_')), - '-sub' if subrepos else '', - safe_str(commit.short_id), ext) + try: + at_path = commit.get_node(at_path).path or default_at_path + except Exception: + return Response(_('No node at path {} for this repository').format(at_path)) + + path_sha = sha1(at_path)[:8] + + # original backward compat name of archive + clean_name = safe_str(self.db_repo_name.replace('/', '_')) + short_sha = safe_str(commit.short_id) + + if at_path == default_at_path: + archive_name = '{}-{}{}{}'.format( + clean_name, + '-sub' if subrepos else '', + short_sha, + ext) + # custom path and new name + else: + archive_name = '{}-{}{}-{}{}'.format( + clean_name, + '-sub' if subrepos else '', + short_sha, + path_sha, + ext) use_cached_archive = False archive_cache_enabled = CONFIG.get( @@ -339,7 +388,8 @@ class RepoFilesView(RepoAppView): fd, archive = tempfile.mkstemp() log.debug('Creating new temp archive in %s', archive) try: - commit.archive_repo(archive, kind=fileformat, subrepos=subrepos) + commit.archive_repo(archive, kind=fileformat, subrepos=subrepos, + archive_at_path=at_path) except ImproperArchiveTypeError: return _('Unknown archive type') if archive_cache_enabled: @@ -632,8 +682,7 @@ class RepoFilesView(RepoAppView): c.authors = [] # this loads a simple tree without metadata to speed things up # later via ajax we call repo_nodetree_full and fetch whole - c.file_tree = self._get_tree_at_commit( - c, c.commit.raw_id, f_path) + c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path) except RepositoryError as e: h.flash(safe_str(h.escape(e)), category='error') @@ -875,18 +924,17 @@ class RepoFilesView(RepoAppView): self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path) return {'nodes': metadata} - def _create_references( - self, branches_or_tags, symbolic_reference, f_path): + def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type): items = [] for name, commit_id in branches_or_tags.items(): - sym_ref = symbolic_reference(commit_id, name, f_path) - items.append((sym_ref, name)) + sym_ref = symbolic_reference(commit_id, name, f_path, ref_type) + items.append((sym_ref, name, ref_type)) return items - def _symbolic_reference(self, commit_id, name, f_path): + def _symbolic_reference(self, commit_id, name, f_path, ref_type): return commit_id - def _symbolic_reference_svn(self, commit_id, name, f_path): + def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type): new_f_path = vcspath.join(name, f_path) return u'%s@%s' % (new_f_path, commit_id) @@ -916,7 +964,7 @@ class RepoFilesView(RepoAppView): for commit in commits: branch = ' (%s)' % commit.branch if commit.branch else '' n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch) - commits_group[0].append((commit.raw_id, n_desc,)) + commits_group[0].append((commit.raw_id, n_desc, 'sha')) history.append(commits_group) symbolic_reference = self._symbolic_reference @@ -932,11 +980,11 @@ class RepoFilesView(RepoAppView): symbolic_reference = self._symbolic_reference_svn branches = self._create_references( - self.rhodecode_vcs_repo.branches, symbolic_reference, f_path) + self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch') branches_group = (branches, _("Branches")) tags = self._create_references( - self.rhodecode_vcs_repo.tags, symbolic_reference, f_path) + self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag') tags_group = (tags, _("Tags")) history.append(branches_group) @@ -964,7 +1012,7 @@ class RepoFilesView(RepoAppView): for obj in file_history: res.append({ 'text': obj[1], - 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]] + 'children': [{'id': o[0], 'text': o[1], 'type': o[2]} for o in obj[0]] }) data = { @@ -1035,15 +1083,9 @@ class RepoFilesView(RepoAppView): _branch_name, _sha_commit_id, is_head = \ self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - if not is_head: - h.flash(_('You can only delete files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) + self.forbid_non_head(is_head, f_path) + self.check_branch_permission(_branch_name) - self.check_branch_permission(_branch_name) c.commit = self._get_commit_or_redirect(commit_id) c.file = self._get_filenode_or_redirect(c.commit, f_path) @@ -1069,13 +1111,7 @@ class RepoFilesView(RepoAppView): _branch_name, _sha_commit_id, is_head = \ self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - if not is_head: - h.flash(_('You can only delete files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) + self.forbid_non_head(is_head, f_path) self.check_branch_permission(_branch_name) c.commit = self._get_commit_or_redirect(commit_id) @@ -1125,14 +1161,8 @@ class RepoFilesView(RepoAppView): _branch_name, _sha_commit_id, is_head = \ self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - if not is_head: - h.flash(_('You can only edit files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) - self.check_branch_permission(_branch_name) + self.forbid_non_head(is_head, f_path, commit_id=commit_id) + self.check_branch_permission(_branch_name, commit_id=commit_id) c.commit = self._get_commit_or_redirect(commit_id) c.file = self._get_filenode_or_redirect(c.commit, f_path) @@ -1144,8 +1174,7 @@ class RepoFilesView(RepoAppView): commit_id=c.commit.raw_id, f_path=f_path) raise HTTPFound(files_url) - c.default_message = _( - 'Edited file {} via RhodeCode Enterprise').format(f_path) + c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path) c.f_path = f_path return self._get_template_context(c) @@ -1162,32 +1191,23 @@ class RepoFilesView(RepoAppView): commit_id, f_path = self._get_commit_and_path() self._ensure_not_locked() - _branch_name, _sha_commit_id, is_head = \ - self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - - if not is_head: - h.flash(_('You can only edit files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) - - self.check_branch_permission(_branch_name) c.commit = self._get_commit_or_redirect(commit_id) c.file = self._get_filenode_or_redirect(c.commit, f_path) if c.file.is_binary: - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, - commit_id=c.commit.raw_id, - f_path=f_path)) + raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name, + commit_id=c.commit.raw_id, f_path=f_path)) + + _branch_name, _sha_commit_id, is_head = \ + self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - c.default_message = _( - 'Edited file {} via RhodeCode Enterprise').format(f_path) + self.forbid_non_head(is_head, f_path, commit_id=commit_id) + self.check_branch_permission(_branch_name, commit_id=commit_id) + + c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path) c.f_path = f_path + old_content = c.file.content sl = old_content.splitlines(1) first_line = sl[0] if sl else '' @@ -1198,20 +1218,25 @@ class RepoFilesView(RepoAppView): content = convert_line_endings(r_post.get('content', ''), line_ending_mode) message = r_post.get('message') or c.default_message - org_f_path = c.file.unicode_path + org_node_path = c.file.unicode_path filename = r_post['filename'] - org_filename = c.file.name + + root_path = c.file.dir_path + pure_path = self.create_pure_path(root_path, filename) + node_path = safe_unicode(bytes(pure_path)) - if content == old_content and filename == org_filename: - h.flash(_('No changes'), category='warning') - raise HTTPFound( - h.route_path('repo_commit', repo_name=self.db_repo_name, - commit_id='tip')) + default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name, + commit_id=commit_id) + if content == old_content and node_path == org_node_path: + h.flash(_('No changes detected on {}').format(org_node_path), + category='warning') + raise HTTPFound(default_redirect_url) + try: mapping = { - org_f_path: { - 'org_filename': org_f_path, - 'filename': os.path.join(c.file.dir_path, filename), + org_node_path: { + 'org_filename': org_node_path, + 'filename': node_path, 'content': content, 'lexer': '', 'op': 'mod', @@ -1219,7 +1244,7 @@ class RepoFilesView(RepoAppView): } } - ScmModel().update_nodes( + commit = ScmModel().update_nodes( user=self._rhodecode_db_user.user_id, repo=self.db_repo, message=message, @@ -1227,21 +1252,25 @@ class RepoFilesView(RepoAppView): parent_commit=c.commit, ) - h.flash( - _('Successfully committed changes to file `{}`').format( + h.flash(_('Successfully committed changes to file `{}`').format( h.escape(f_path)), category='success') + default_redirect_url = h.route_path( + 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id) + except Exception: log.exception('Error occurred during commit') h.flash(_('Error occurred during commit'), category='error') - raise HTTPFound( - h.route_path('repo_commit', repo_name=self.db_repo_name, - commit_id='tip')) + + raise HTTPFound(default_redirect_url) @LoginRequired() @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') @view_config( route_name='repo_files_add_file', request_method='GET', renderer='rhodecode:templates/files/files_add.mako') + @view_config( + route_name='repo_files_upload_file', request_method='GET', + renderer='rhodecode:templates/files/files_upload.mako') def repo_files_add_file(self): _ = self.request.translate c = self.load_default_context() @@ -1252,27 +1281,20 @@ class RepoFilesView(RepoAppView): c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False) if c.commit is None: c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias) - c.default_message = (_('Added file via RhodeCode Enterprise')) - c.f_path = f_path.lstrip('/') # ensure not relative path - if self.rhodecode_vcs_repo.is_empty: + if self.rhodecode_vcs_repo.is_empty(): # for empty repository we cannot check for current branch, we rely on # c.commit.branch instead - _branch_name = c.commit.branch - is_head = True + _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True else: _branch_name, _sha_commit_id, is_head = \ self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - if not is_head: - h.flash(_('You can only add files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) + self.forbid_non_head(is_head, f_path, commit_id=commit_id) + self.check_branch_permission(_branch_name, commit_id=commit_id) - self.check_branch_permission(_branch_name) + c.default_message = (_('Added file via RhodeCode Enterprise')) + c.f_path = f_path.lstrip('/') # ensure not relative path return self._get_template_context(c) @@ -1289,86 +1311,62 @@ class RepoFilesView(RepoAppView): self._ensure_not_locked() - r_post = self.request.POST - - c.commit = self._get_commit_or_redirect( - commit_id, redirect_after=False) + c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False) if c.commit is None: c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias) - if self.rhodecode_vcs_repo.is_empty: - # for empty repository we cannot check for current branch, we rely on - # c.commit.branch instead - _branch_name = c.commit.branch - is_head = True - else: - _branch_name, _sha_commit_id, is_head = \ - self._is_valid_head(commit_id, self.rhodecode_vcs_repo) - - if not is_head: - h.flash(_('You can only add files with commit ' - 'being a valid branch head.'), category='warning') - raise HTTPFound( - h.route_path('repo_files', - repo_name=self.db_repo_name, commit_id='tip', - f_path=f_path)) - - self.check_branch_permission(_branch_name) - - c.default_message = (_('Added file via RhodeCode Enterprise')) - c.f_path = f_path - unix_mode = 0 - content = convert_line_endings(r_post.get('content', ''), unix_mode) - - message = r_post.get('message') or c.default_message - filename = r_post.get('filename') - location = r_post.get('location', '') # dir location - file_obj = r_post.get('upload_file', None) - - if file_obj is not None and hasattr(file_obj, 'filename'): - filename = r_post.get('filename_upload') - content = file_obj.file - - if hasattr(content, 'file'): - # non posix systems store real file under file attr - content = content.file - - if self.rhodecode_vcs_repo.is_empty: + # calculate redirect URL + if self.rhodecode_vcs_repo.is_empty(): default_redirect_url = h.route_path( 'repo_summary', repo_name=self.db_repo_name) else: default_redirect_url = h.route_path( 'repo_commit', repo_name=self.db_repo_name, commit_id='tip') - # If there's no commit, redirect to repo summary - if type(c.commit) is EmptyCommit: - redirect_url = h.route_path( - 'repo_summary', repo_name=self.db_repo_name) + if self.rhodecode_vcs_repo.is_empty(): + # for empty repository we cannot check for current branch, we rely on + # c.commit.branch instead + _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True else: - redirect_url = default_redirect_url + _branch_name, _sha_commit_id, is_head = \ + self._is_valid_head(commit_id, self.rhodecode_vcs_repo) + + self.forbid_non_head(is_head, f_path, commit_id=commit_id) + self.check_branch_permission(_branch_name, commit_id=commit_id) + + c.default_message = (_('Added file via RhodeCode Enterprise')) + c.f_path = f_path + + r_post = self.request.POST + message = r_post.get('message') or c.default_message + filename = r_post.get('filename') + unix_mode = 0 + content = convert_line_endings(r_post.get('content', ''), unix_mode) if not filename: - h.flash(_('No filename'), category='warning') + # If there's no commit, redirect to repo summary + if type(c.commit) is EmptyCommit: + redirect_url = h.route_path( + 'repo_summary', repo_name=self.db_repo_name) + else: + redirect_url = default_redirect_url + h.flash(_('No filename specified'), category='warning') raise HTTPFound(redirect_url) - # extract the location from filename, - # allows using foo/bar.txt syntax to create subdirectories - subdir_loc = filename.rsplit('/', 1) - if len(subdir_loc) == 2: - location = os.path.join(location, subdir_loc[0]) + root_path = f_path + pure_path = self.create_pure_path(root_path, filename) + node_path = safe_unicode(bytes(pure_path).lstrip('/')) - # strip all crap out of file, just leave the basename - filename = os.path.basename(filename) - node_path = os.path.join(location, filename) author = self._rhodecode_db_user.full_contact + nodes = { + node_path: { + 'content': content + } + } try: - nodes = { - node_path: { - 'content': content - } - } - ScmModel().create_nodes( + + commit = ScmModel().create_nodes( user=self._rhodecode_db_user.user_id, repo=self.db_repo, message=message, @@ -1377,14 +1375,16 @@ class RepoFilesView(RepoAppView): author=author, ) - h.flash( - _('Successfully committed new file `{}`').format( + h.flash(_('Successfully committed new file `{}`').format( h.escape(node_path)), category='success') + + default_redirect_url = h.route_path( + 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id) + except NonRelativePathError: log.exception('Non Relative path found') - h.flash(_( - 'The location specified must be a relative path and must not ' - 'contain .. in the path'), category='warning') + h.flash(_('The location specified must be a relative path and must not ' + 'contain .. in the path'), category='warning') raise HTTPFound(default_redirect_url) except (NodeError, NodeAlreadyExistsError) as e: h.flash(_(h.escape(e)), category='error') @@ -1393,3 +1393,134 @@ class RepoFilesView(RepoAppView): h.flash(_('Error occurred during commit'), category='error') raise HTTPFound(default_redirect_url) + + @LoginRequired() + @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') + @CSRFRequired() + @view_config( + route_name='repo_files_upload_file', request_method='POST', + renderer='json_ext') + def repo_files_upload_file(self): + _ = self.request.translate + c = self.load_default_context() + commit_id, f_path = self._get_commit_and_path() + + self._ensure_not_locked() + + c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False) + if c.commit is None: + c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias) + + # calculate redirect URL + if self.rhodecode_vcs_repo.is_empty(): + default_redirect_url = h.route_path( + 'repo_summary', repo_name=self.db_repo_name) + else: + default_redirect_url = h.route_path( + 'repo_commit', repo_name=self.db_repo_name, commit_id='tip') + + if self.rhodecode_vcs_repo.is_empty(): + # for empty repository we cannot check for current branch, we rely on + # c.commit.branch instead + _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True + else: + _branch_name, _sha_commit_id, is_head = \ + self._is_valid_head(commit_id, self.rhodecode_vcs_repo) + + error = self.forbid_non_head(is_head, f_path, json_mode=True) + if error: + return { + 'error': error, + 'redirect_url': default_redirect_url + } + error = self.check_branch_permission(_branch_name, json_mode=True) + if error: + return { + 'error': error, + 'redirect_url': default_redirect_url + } + + c.default_message = (_('Uploaded file via RhodeCode Enterprise')) + c.f_path = f_path + + r_post = self.request.POST + + message = c.default_message + user_message = r_post.getall('message') + if isinstance(user_message, list) and user_message: + # we take the first from duplicated results if it's not empty + message = user_message[0] if user_message[0] else message + + nodes = {} + + for file_obj in r_post.getall('files_upload') or []: + content = file_obj.file + filename = file_obj.filename + + root_path = f_path + pure_path = self.create_pure_path(root_path, filename) + node_path = safe_unicode(bytes(pure_path).lstrip('/')) + + nodes[node_path] = { + 'content': content + } + + if not nodes: + error = 'missing files' + return { + 'error': error, + 'redirect_url': default_redirect_url + } + + author = self._rhodecode_db_user.full_contact + + try: + commit = ScmModel().create_nodes( + user=self._rhodecode_db_user.user_id, + repo=self.db_repo, + message=message, + nodes=nodes, + parent_commit=c.commit, + author=author, + ) + if len(nodes) == 1: + flash_message = _('Successfully committed {} new files').format(len(nodes)) + else: + flash_message = _('Successfully committed 1 new file') + + h.flash(flash_message, category='success') + + default_redirect_url = h.route_path( + 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id) + + except NonRelativePathError: + log.exception('Non Relative path found') + error = _('The location specified must be a relative path and must not ' + 'contain .. in the path') + h.flash(error, category='warning') + + return { + 'error': error, + 'redirect_url': default_redirect_url + } + except (NodeError, NodeAlreadyExistsError) as e: + error = h.escape(e) + h.flash(error, category='error') + + return { + 'error': error, + 'redirect_url': default_redirect_url + } + except Exception: + log.exception('Error occurred during commit') + error = _('Error occurred during commit') + h.flash(error, category='error') + return { + 'error': error, + 'redirect_url': default_redirect_url + } + + return { + 'error': None, + 'redirect_url': default_redirect_url + } diff --git a/rhodecode/apps/repository/views/repo_summary.py b/rhodecode/apps/repository/views/repo_summary.py --- a/rhodecode/apps/repository/views/repo_summary.py +++ b/rhodecode/apps/repository/views/repo_summary.py @@ -72,6 +72,7 @@ class RepoSummaryView(RepoAppView): log.debug("Searching for a README file.") readme_node = ReadmeFinder(_renderer_type).search(commit) if readme_node: + log.debug('Found README node: %s', readme_node) relative_urls = { 'raw': h.route_path( 'repo_file_raw', repo_name=_repo_name, @@ -82,7 +83,8 @@ class RepoSummaryView(RepoAppView): } readme_data = self._render_readme_or_none( commit, readme_node, relative_urls) - readme_filename = readme_node.path + readme_filename = readme_node.unicode_path + return readme_data, readme_filename inv_context_manager = rc_cache.InvalidationContext( @@ -202,6 +204,10 @@ class RepoSummaryView(RepoAppView): # Prepare the clone URL self._prepare_and_set_clone_url(c) + # update every 5 min + if self.db_repo.last_commit_cache_update_diff > 60 * 5: + self.db_repo.update_commit_cache() + # If enabled, get statistics data c.show_stats = bool(self.db_repo.enable_statistics) @@ -233,8 +239,6 @@ class RepoSummaryView(RepoAppView): c.enable_downloads = self.db_repo.enable_downloads c.repository_followers = scm_model.get_followers(self.db_repo) c.repository_forks = scm_model.get_forks(self.db_repo) - c.repository_is_user_following = scm_model.is_following_repo( - self.db_repo_name, self._rhodecode_user.user_id) # first interaction with the VCS instance after here... if c.repository_requirements_missing: @@ -319,8 +323,7 @@ class RepoSummaryView(RepoAppView): (_("Tag"), repo.tags, 'tag'), (_("Bookmark"), repo.bookmarks, 'book'), ] - res = self._create_reference_data( - repo, self.db_repo_name, refs_to_create) + res = self._create_reference_data(repo, self.db_repo_name, refs_to_create) data = { 'more': False, 'results': res @@ -367,8 +370,7 @@ class RepoSummaryView(RepoAppView): }) return result - def _create_reference_items(self, repo, full_repo_name, refs, ref_type, - format_ref_id): + def _create_reference_items(self, repo, full_repo_name, refs, ref_type, format_ref_id): result = [] is_svn = h.is_svn(repo) for ref_name, raw_id in refs.iteritems(): @@ -380,6 +382,7 @@ class RepoSummaryView(RepoAppView): 'raw_id': raw_id, 'type': ref_type, 'files_url': files_url, + 'idx': 0, }) return result diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py --- a/rhodecode/config/middleware.py +++ b/rhodecode/config/middleware.py @@ -250,7 +250,7 @@ def includeme(config): # Includes which are required. The application would fail without them. config.include('pyramid_mako') - config.include('pyramid_beaker') + config.include('rhodecode.lib.rc_beaker') config.include('rhodecode.lib.rc_cache') config.include('rhodecode.apps._base.navigation') diff --git a/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py b/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py --- a/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py +++ b/rhodecode/config/rcextensions/examples/validate_pushed_files_name_and_size.py @@ -28,8 +28,8 @@ def _pre_push_hook(*args, **kwargs): [{u'hg_env|git_env': ..., u'multiple_heads': [], u'name': u'default', - u'new_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', - u'old_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', + u'new_rev': u'd0b2ae0692e722e01d5677f27a104631cf798b69', + u'old_rev': u'd0b1ae0692e722e01d5677f27a104631cf798b69', u'ref': u'', u'total_commits': 2, u'type': u'branch'}] @@ -47,13 +47,17 @@ def _pre_push_hook(*args, **kwargs): forbid_files = repo_extra_fields.get('forbid_files_glob', {}).get('field_value') forbid_files = aslist(forbid_files) + # forbid_files = ['*'] # example pattern + # optionally get bytes limit for a single file, e.g 1024 for 1KB forbid_size_over = repo_extra_fields.get('forbid_size_over', {}).get('field_value') forbid_size_over = int(forbid_size_over or 0) + # forbid_size_over = 1024 # example 1024 + def validate_file_name_and_size(file_data, forbidden_files=None, size_limit=None): """ - This function validates commited files against some sort of rules. + This function validates comited files against some sort of rules. It should return a valid boolean, and a reason for failure file_data =[ @@ -87,7 +91,10 @@ def _pre_push_hook(*args, **kwargs): # validate A(dded) files and size if size_limit and operation == 'A': - size = len(file_data['raw_diff']) + if 'file_size' in file_data: + size = file_data['file_size'] + else: + size = len(file_data['raw_diff']) reason = 'File {} size of {} bytes exceeds limit {}'.format( file_name, format_byte_size_binary(size), diff --git a/rhodecode/config/rcextensions/helpers/extract_pre_files.py b/rhodecode/config/rcextensions/helpers/extract_pre_files.py --- a/rhodecode/config/rcextensions/helpers/extract_pre_files.py +++ b/rhodecode/config/rcextensions/helpers/extract_pre_files.py @@ -34,12 +34,51 @@ from rhodecode.lib.vcs.backends.hg.diff from rhodecode.lib.vcs.backends.git.diff import GitDiff -def get_hg_files(repo, refs): +def get_svn_files(repo, vcs_repo, refs): + txn_id = refs[0] + files = [] + stdout, stderr = vcs_repo.run_svn_command( + ['svnlook', 'changed', repo.repo_full_path, '--transaction', txn_id]) + + svn_op_to_rc_op = { + 'A': 'A', + 'U': 'M', + 'D': 'D', + } + + for entry in stdout.splitlines(): + parsed_entry = { + 'raw_diff': '', + 'filename': '', + 'chunks': [], + 'ops': {}, + 'file_size': 0 + } + + op = entry[0] + path = entry[1:].strip() + + rc_op = svn_op_to_rc_op.get(op) or '?' + parsed_entry['filename'] = path + parsed_entry['operation'] = rc_op + + if rc_op in ['A', 'M']: + stdout, stderr = vcs_repo.run_svn_command( + ['svnlook', 'filesize', repo.repo_full_path, path, '--transaction', txn_id]) + file_size = int(stdout.strip()) + parsed_entry['file_size'] = file_size + + files.append(parsed_entry) + + return files + + +def get_hg_files(repo, vcs_repo, refs): files = [] return files -def get_git_files(repo, refs): +def get_git_files(repo, vcs_repo, refs): files = [] for data in refs: @@ -57,7 +96,7 @@ def get_git_files(repo, refs): 'diff', old_rev, new_rev ] - stdout, stderr = repo.run_git_command(cmd, extra_env=git_env) + stdout, stderr = vcs_repo.run_git_command(cmd, extra_env=git_env) vcs_diff = GitDiff(stdout) diff_processor = diffs.DiffProcessor(vcs_diff, format='newdiff') @@ -86,11 +125,14 @@ def run(*args, **kwargs): if vcs_type == 'git': for rev_data in kwargs['commit_ids']: new_environ = dict((k, v) for k, v in rev_data['git_env']) - files = get_git_files(vcs_repo, kwargs['commit_ids']) + files = get_git_files(repo, vcs_repo, kwargs['commit_ids']) if vcs_type == 'hg': for rev_data in kwargs['commit_ids']: new_environ = dict((k, v) for k, v in rev_data['hg_env']) - files = get_hg_files(vcs_repo, kwargs['commit_ids']) + files = get_hg_files(repo, vcs_repo, kwargs['commit_ids']) + + if vcs_type == 'svn': + files = get_svn_files(repo, vcs_repo, kwargs['commit_ids']) return files diff --git a/rhodecode/integrations/views.py b/rhodecode/integrations/views.py --- a/rhodecode/integrations/views.py +++ b/rhodecode/integrations/views.py @@ -402,7 +402,8 @@ class RepoIntegrationsView(IntegrationSe c.rhodecode_db_repo = self.repo c.repo_name = self.db_repo.repo_name c.repository_pull_requests = ScmModel().get_pull_requests(self.repo) - + c.repository_is_user_following = ScmModel().is_following_repo( + c.repo_name, self._rhodecode_user.user_id) c.has_origin_repo_read_perm = False if self.db_repo.fork: c.has_origin_repo_read_perm = h.HasRepoPermissionAny( diff --git a/rhodecode/lib/audit_logger.py b/rhodecode/lib/audit_logger.py --- a/rhodecode/lib/audit_logger.py +++ b/rhodecode/lib/audit_logger.py @@ -92,6 +92,9 @@ ACTIONS_V1 = { 'repo.commit.comment.delete': {'data': {}}, 'repo.commit.vote': '', + 'repo.artifact.add': '', + 'repo.artifact.delete': '', + 'repo_group.create': {'data': {}}, 'repo_group.edit': {'old_data': {}}, 'repo_group.edit.permissions': {}, diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -2078,8 +2078,7 @@ class HasRepoPermissionAny(PermsFunction class HasRepoGroupPermissionAny(PermsFunction): def __call__(self, group_name=None, check_location='', user=None): self.repo_group_name = group_name - return super(HasRepoGroupPermissionAny, self).__call__( - check_location, user) + return super(HasRepoGroupPermissionAny, self).__call__(check_location, user) def check_permissions(self, user): perms = user.permissions @@ -2095,8 +2094,7 @@ class HasRepoGroupPermissionAny(PermsFun class HasRepoGroupPermissionAll(PermsFunction): def __call__(self, group_name=None, check_location='', user=None): self.repo_group_name = group_name - return super(HasRepoGroupPermissionAll, self).__call__( - check_location, user) + return super(HasRepoGroupPermissionAll, self).__call__(check_location, user) def check_permissions(self, user): perms = user.permissions @@ -2112,8 +2110,7 @@ class HasRepoGroupPermissionAll(PermsFun class HasUserGroupPermissionAny(PermsFunction): def __call__(self, user_group_name=None, check_location='', user=None): self.user_group_name = user_group_name - return super(HasUserGroupPermissionAny, self).__call__( - check_location, user) + return super(HasUserGroupPermissionAny, self).__call__(check_location, user) def check_permissions(self, user): perms = user.permissions @@ -2129,8 +2126,7 @@ class HasUserGroupPermissionAny(PermsFun class HasUserGroupPermissionAll(PermsFunction): def __call__(self, user_group_name=None, check_location='', user=None): self.user_group_name = user_group_name - return super(HasUserGroupPermissionAll, self).__call__( - check_location, user) + return super(HasUserGroupPermissionAll, self).__call__(check_location, user) def check_permissions(self, user): perms = user.permissions diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py --- a/rhodecode/lib/base.py +++ b/rhodecode/lib/base.py @@ -288,7 +288,6 @@ def attach_context_attributes(context, r """ config = request.registry.settings - rc_config = SettingsModel().get_all_settings(cache=True) context.rhodecode_version = rhodecode.__version__ @@ -375,20 +374,25 @@ def attach_context_attributes(context, r "sideside": "sideside" }.get(request.GET.get('diffmode')) - if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'): - request.session['rc_user_session_attr.diffmode'] = diffmode - - # session settings per user + is_api = hasattr(request, 'rpc_user') session_attrs = { # defaults "clone_url_format": "http", "diffmode": "sideside" } - for k, v in request.session.items(): - pref = 'rc_user_session_attr.' - if k and k.startswith(pref): - k = k[len(pref):] - session_attrs[k] = v + + if not is_api: + # don't access pyramid session for API calls + if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'): + request.session['rc_user_session_attr.diffmode'] = diffmode + + # session settings per user + + for k, v in request.session.items(): + pref = 'rc_user_session_attr.' + if k and k.startswith(pref): + k = k[len(pref):] + session_attrs[k] = v context.user_session_attrs = session_attrs @@ -420,8 +424,12 @@ def attach_context_attributes(context, r 'extra': {'plugins': {}} } # END CONFIG VARS + if is_api: + csrf_token = None + else: + csrf_token = auth.get_csrf_token(session=request.session) - context.csrf_token = auth.get_csrf_token(session=request.session) + context.csrf_token = csrf_token context.backends = rhodecode.BACKENDS.keys() context.backends.sort() unread_count = 0 @@ -537,7 +545,7 @@ def bootstrap_config(request): # allow pyramid lookup in testing config.include('pyramid_mako') - config.include('pyramid_beaker') + config.include('rhodecode.lib.rc_beaker') config.include('rhodecode.lib.rc_cache') add_events_routes(config) diff --git a/rhodecode/lib/db_manage.py b/rhodecode/lib/db_manage.py --- a/rhodecode/lib/db_manage.py +++ b/rhodecode/lib/db_manage.py @@ -485,9 +485,6 @@ class DbManage(object): self.populate_default_permissions() return fixed - def update_repo_info(self): - RepoModel.update_repoinfo() - def config_prompt(self, test_repo_path='', retries=3): defaults = self.cli_args _path = defaults.get('repos_location') diff --git a/rhodecode/lib/dbmigrate/schema/db_1_6_0.py b/rhodecode/lib/dbmigrate/schema/db_1_6_0.py --- a/rhodecode/lib/dbmigrate/schema/db_1_6_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_1_6_0.py @@ -614,7 +614,7 @@ class Repository(Base, BaseModel): if (cs_cache != self.changeset_cache or not self.changeset_cache): _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', self.repo_name, cs_cache) + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache Session().add(self) diff --git a/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py @@ -2164,7 +2164,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py @@ -2230,7 +2230,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py @@ -2278,7 +2278,7 @@ class Repository(Base, BaseModel): # if yes, we use the current timestamp instead. Imagine you get # old commit pushed 1y ago, we'd set last update 1y to ago. last_change = _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py --- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py @@ -2301,7 +2301,7 @@ class Repository(Base, BaseModel): # if yes, we use the current timestamp instead. Imagine you get # old commit pushed 1y ago, we'd set last update 1y to ago. last_change = _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py --- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py @@ -2301,7 +2301,7 @@ class Repository(Base, BaseModel): # if yes, we use the current timestamp instead. Imagine you get # old commit pushed 1y ago, we'd set last update 1y to ago. last_change = _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py @@ -1865,7 +1865,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py @@ -1868,7 +1868,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py --- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py @@ -1867,7 +1867,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py --- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py @@ -1869,7 +1869,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py @@ -1869,7 +1869,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py @@ -1912,7 +1912,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py --- a/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py @@ -1913,7 +1913,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py --- a/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py +++ b/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py @@ -2100,7 +2100,7 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.fromtimestamp(0) last_change = cs_cache.get('date') or _default - log.debug('updated repo %s with new cs cache %s', + log.debug('updated repo %s with new commit cache %s', self.repo_name, cs_cache) self.updated_on = last_change self.changeset_cache = cs_cache diff --git a/rhodecode/lib/dbmigrate/versions/096_version_4_17_0.py b/rhodecode/lib/dbmigrate/versions/096_version_4_17_0.py --- a/rhodecode/lib/dbmigrate/versions/096_version_4_17_0.py +++ b/rhodecode/lib/dbmigrate/versions/096_version_4_17_0.py @@ -8,6 +8,7 @@ from sqlalchemy import String, Column from sqlalchemy.sql import text from rhodecode.lib.dbmigrate.versions import _reset_base +from rhodecode.lib.utils2 import safe_str from rhodecode.model import meta, init_model_encryption from rhodecode.model.db import RepoGroup @@ -29,7 +30,7 @@ def upgrade(migrate_engine): op = Operations(context) repo_group = db_4_16_0_2.RepoGroup.__table__ - + with op.batch_alter_table(repo_group.name) as batch_op: batch_op.add_column( Column("repo_group_name_hash", String(1024), nullable=True, unique=False)) @@ -44,7 +45,7 @@ def downgrade(migrate_engine): def _generate_repo_group_name_hashes(models, op, session): repo_groups = models.RepoGroup.get_all() for repo_group in repo_groups: - print(repo_group.group_name) + print(safe_str(repo_group.group_name)) hash_ = RepoGroup.hash_repo_group_name(repo_group.group_name) params = {'hash': hash_, 'id': repo_group.group_id} query = text( diff --git a/rhodecode/lib/dbmigrate/versions/097_version_4_17_0.py b/rhodecode/lib/dbmigrate/versions/097_version_4_17_0.py --- a/rhodecode/lib/dbmigrate/versions/097_version_4_17_0.py +++ b/rhodecode/lib/dbmigrate/versions/097_version_4_17_0.py @@ -26,14 +26,10 @@ def upgrade(migrate_engine): op = Operations(context) repo_group = db_4_16_0_2.RepoGroup.__table__ - + with op.batch_alter_table(repo_group.name) as batch_op: batch_op.alter_column("repo_group_name_hash", nullable=False) def downgrade(migrate_engine): pass - - -def _generate_repo_group_name_hashes(models, op, session): - pass diff --git a/rhodecode/lib/dbmigrate/versions/098_version_4_17_0.py b/rhodecode/lib/dbmigrate/versions/098_version_4_17_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/098_version_4_17_0.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import logging + +from alembic.migration import MigrationContext +from alembic.operations import Operations +from sqlalchemy import Column, LargeBinary + +from rhodecode.lib.dbmigrate.versions import _reset_base +from rhodecode.model import init_model_encryption + + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_4_16_0_2 + + init_model_encryption(db_4_16_0_2) + + context = MigrationContext.configure(migrate_engine.connect()) + op = Operations(context) + + repo_group = db_4_16_0_2.RepoGroup.__table__ + + with op.batch_alter_table(repo_group.name) as batch_op: + batch_op.add_column( + Column("changeset_cache", LargeBinary(1024), nullable=True)) + + +def downgrade(migrate_engine): + pass diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -199,6 +199,7 @@ class _GetError(object): if form_errors and field_name in form_errors: return literal(tmpl % form_errors.get(field_name)) + get_error = _GetError() @@ -214,38 +215,45 @@ class _ToolTip(object): tooltip_title = escape(tooltip_title) tooltip_title = tooltip_title.replace('<', '<').replace('>', '>') return tooltip_title + + tooltip = _ToolTip() +files_icon = u'' -def files_breadcrumbs(repo_name, commit_id, file_path): + +def files_breadcrumbs(repo_name, commit_id, file_path, at_ref=None, limit_items=False, linkify_last_item=False): if isinstance(file_path, str): file_path = safe_unicode(file_path) - # TODO: johbo: Is this always a url like path, or is this operating - # system dependent? - path_segments = file_path.split('/') + route_qry = {'at': at_ref} if at_ref else None - repo_name_html = escape(repo_name) - if len(path_segments) == 1 and path_segments[0] == '': - url_segments = [repo_name_html] - else: - url_segments = [ - link_to( - repo_name_html, - route_path( - 'repo_files', - repo_name=repo_name, - commit_id=commit_id, - f_path=''), - class_='pjax-link')] + # first segment is a `..` link to repo files + root_name = literal(u'') + url_segments = [ + link_to( + root_name, + route_path( + 'repo_files', + repo_name=repo_name, + commit_id=commit_id, + f_path='', + _query=route_qry), + )] + path_segments = file_path.split('/') last_cnt = len(path_segments) - 1 for cnt, segment in enumerate(path_segments): if not segment: continue segment_html = escape(segment) - if cnt != last_cnt: + last_item = cnt == last_cnt + + if last_item and linkify_last_item is False: + # plain version + url_segments.append(segment_html) + else: url_segments.append( link_to( segment_html, @@ -253,12 +261,32 @@ def files_breadcrumbs(repo_name, commit_ 'repo_files', repo_name=repo_name, commit_id=commit_id, - f_path='/'.join(path_segments[:cnt + 1])), - class_='pjax-link')) - else: - url_segments.append(segment_html) + f_path='/'.join(path_segments[:cnt + 1]), + _query=route_qry), + )) + + limited_url_segments = url_segments[:1] + ['...'] + url_segments[-5:] + if limit_items and len(limited_url_segments) < len(url_segments): + url_segments = limited_url_segments - return literal('/'.join(url_segments)) + full_path = file_path + icon = files_icon.format(escape(full_path)) + if file_path == '': + return root_name + else: + return literal(' / '.join(url_segments) + icon) + + +def files_url_data(request): + matchdict = request.matchdict + + if 'f_path' not in matchdict: + matchdict['f_path'] = '' + + if 'commit_id' not in matchdict: + matchdict['commit_id'] = 'tip' + + return json.dumps(matchdict) def code_highlight(code, lexer, formatter, use_hl_filter=False): @@ -1196,7 +1224,7 @@ class InitialsGravatar(object): """.format( size=self.size, - f_size=self.size/1.85, # scale the text inside the box nicely + f_size=self.size/2.05, # scale the text inside the box nicely background=self.background, text_color=self.text_color, text=initials.upper(), @@ -1486,10 +1514,12 @@ def breadcrumb_repo_link(repo): """ path = [ - link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name)) + link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name), + title='last change:{}'.format(format_date(group.last_commit_change))) for group in repo.groups_with_parents ] + [ - link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name)) + link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name), + title='last change:{}'.format(format_date(repo.last_commit_change))) ] return literal(' » '.join(path)) @@ -1507,11 +1537,13 @@ def breadcrumb_repo_group_link(repo_grou path = [ link_to(group.name, - route_path('repo_group_home', repo_group_name=group.group_name)) + route_path('repo_group_home', repo_group_name=group.group_name), + title='last change:{}'.format(format_date(group.last_commit_change))) for group in repo_group.parents ] + [ link_to(repo_group.name, - route_path('repo_group_home', repo_group_name=repo_group.group_name)) + route_path('repo_group_home', repo_group_name=repo_group.group_name), + title='last change:{}'.format(format_date(repo_group.last_commit_change))) ] return literal(' » '.join(path)) @@ -1907,23 +1939,26 @@ def secure_form(form_url, method="POST", def dropdownmenu(name, selected, options, enable_filter=False, **attrs): select_html = select(name, selected, options, **attrs) + select2 = """ """ + filter_option = """, minimumResultsForSearch: -1 """ input_id = attrs.get('id') or name + extra_classes = ' '.join(attrs.pop('extra_classes', [])) filter_enabled = "" if enable_filter else filter_option - select_script = literal(select2 % (input_id, filter_enabled)) + select_script = literal(select2 % (input_id, extra_classes, filter_enabled)) return literal(select_html+select_script) @@ -1944,7 +1979,7 @@ def get_visual_attr(tmpl_context_var, at def get_last_path_part(file_node): if not file_node.path: - return u'' + return u'/' path = safe_unicode(file_node.path.split('/')[-1]) return u'../' + path @@ -2033,7 +2068,8 @@ def reviewer_as_json(*args, **kwargs): def get_repo_view_type(request): route_name = request.matched_route.name route_to_view_type = { - 'repo_changelog': 'changelog', + 'repo_changelog': 'commits', + 'repo_commits': 'commits', 'repo_files': 'files', 'repo_summary': 'summary', 'repo_commit': 'commit' diff --git a/rhodecode/lib/markdown_ext.py b/rhodecode/lib/markdown_ext.py --- a/rhodecode/lib/markdown_ext.py +++ b/rhodecode/lib/markdown_ext.py @@ -20,7 +20,55 @@ import markdown -from mdx_gfm import GithubFlavoredMarkdownExtension # pragma: no cover +from markdown.extensions import Extension +from markdown.extensions.fenced_code import FencedCodeExtension +from markdown.extensions.smart_strong import SmartEmphasisExtension +from markdown.extensions.tables import TableExtension +from markdown.extensions.nl2br import Nl2BrExtension + +import gfm + + +class GithubFlavoredMarkdownExtension(Extension): + """ + An extension that is as compatible as possible with GitHub-flavored + Markdown (GFM). + + This extension aims to be compatible with the variant of GFM that GitHub + uses for Markdown-formatted gists and files (including READMEs). This + variant seems to have all the extensions described in the `GFM + documentation`_, except: + + - Newlines in paragraphs are not transformed into ``br`` tags. + - Intra-GitHub links to commits, repositories, and issues are not + supported. + + If you need support for features specific to GitHub comments and issues, + please use :class:`mdx_gfm.GithubFlavoredMarkdownExtension`. + + .. _GFM documentation: https://guides.github.com/features/mastering-markdown/ + """ + + def extendMarkdown(self, md, md_globals): + # Built-in extensions + FencedCodeExtension().extendMarkdown(md, md_globals) + SmartEmphasisExtension().extendMarkdown(md, md_globals) + TableExtension().extendMarkdown(md, md_globals) + + # Custom extensions + gfm.AutolinkExtension().extendMarkdown(md, md_globals) + gfm.AutomailExtension().extendMarkdown(md, md_globals) + gfm.HiddenHiliteExtension([ + ('guess_lang', 'False'), + ('css_class', 'highlight') + ]).extendMarkdown(md, md_globals) + gfm.SemiSaneListExtension().extendMarkdown(md, md_globals) + gfm.SpacedLinkExtension().extendMarkdown(md, md_globals) + gfm.StrikethroughExtension().extendMarkdown(md, md_globals) + gfm.TaskListExtension([ + ('list_attrs', {'class': 'checkbox'}) + ]).extendMarkdown(md, md_globals) + Nl2BrExtension().extendMarkdown(md, md_globals) # Global Vars diff --git a/rhodecode/lib/rc_beaker.py b/rhodecode/lib/rc_beaker.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/rc_beaker.py @@ -0,0 +1,200 @@ +# Copyright (c) 2010 Agendaless Consulting and Contributors. +# (http://www.agendaless.com), All Rights Reserved +# License: BSD-derived (http://www.repoze.org/LICENSE.txt) +# With Patches from RhodeCode GmBH + + +import os + +from beaker import cache +from beaker.session import SessionObject +from beaker.util import coerce_cache_params +from beaker.util import coerce_session_params + +from pyramid.interfaces import ISession +from pyramid.settings import asbool +from zope.interface import implementer + +from binascii import hexlify + + +def BeakerSessionFactoryConfig(**options): + """ Return a Pyramid session factory using Beaker session settings + supplied directly as ``**options``""" + + class PyramidBeakerSessionObject(SessionObject): + _options = options + _cookie_on_exception = _options.pop('cookie_on_exception', True) + _constant_csrf_token = _options.pop('constant_csrf_token', False) + + def __init__(self, request): + SessionObject.__init__(self, request.environ, **self._options) + + def session_callback(request, response): + exception = getattr(request, 'exception', None) + if (exception is None or self._cookie_on_exception) and self.accessed(): + self.persist() + headers = self.__dict__['_headers'] + if headers['set_cookie'] and headers['cookie_out']: + response.headerlist.append(('Set-Cookie', headers['cookie_out'])) + request.add_response_callback(session_callback) + + # ISession API + + @property + def id(self): + # this is as inspected in SessionObject.__init__ + if self.__dict__['_params'].get('type') != 'cookie': + return self._session().id + return None + + @property + def new(self): + return self.last_accessed is None + + changed = SessionObject.save + + # modifying dictionary methods + + @call_save + def clear(self): + return self._session().clear() + + @call_save + def update(self, d, **kw): + return self._session().update(d, **kw) + + @call_save + def setdefault(self, k, d=None): + return self._session().setdefault(k, d) + + @call_save + def pop(self, k, d=None): + return self._session().pop(k, d) + + @call_save + def popitem(self): + return self._session().popitem() + + __setitem__ = call_save(SessionObject.__setitem__) + __delitem__ = call_save(SessionObject.__delitem__) + + # Flash API methods + def flash(self, msg, queue='', allow_duplicate=True): + storage = self.setdefault('_f_' + queue, []) + if allow_duplicate or (msg not in storage): + storage.append(msg) + + def pop_flash(self, queue=''): + storage = self.pop('_f_' + queue, []) + return storage + + def peek_flash(self, queue=''): + storage = self.get('_f_' + queue, []) + return storage + + # CSRF API methods + def new_csrf_token(self): + token = (self._constant_csrf_token + or hexlify(os.urandom(20)).decode('ascii')) + self['_csrft_'] = token + return token + + def get_csrf_token(self): + token = self.get('_csrft_', None) + if token is None: + token = self.new_csrf_token() + return token + + return implementer(ISession)(PyramidBeakerSessionObject) + + +def call_save(wrapped): + """ By default, in non-auto-mode beaker badly wants people to + call save even though it should know something has changed when + a mutating method is called. This hack should be removed if + Beaker ever starts to do this by default. """ + def save(session, *arg, **kw): + value = wrapped(session, *arg, **kw) + session.save() + return value + save.__doc__ = wrapped.__doc__ + return save + + +def session_factory_from_settings(settings): + """ Return a Pyramid session factory using Beaker session settings + supplied from a Paste configuration file""" + prefixes = ('session.', 'beaker.session.') + options = {} + + # Pull out any config args meant for beaker session. if there are any + for k, v in settings.items(): + for prefix in prefixes: + if k.startswith(prefix): + option_name = k[len(prefix):] + if option_name == 'cookie_on_exception': + v = asbool(v) + options[option_name] = v + + options = coerce_session_params(options) + return BeakerSessionFactoryConfig(**options) + + +def set_cache_regions_from_settings(settings): + """ Add cache support to the Pylons application. + + The ``settings`` passed to the configurator are used to setup + the cache options. Cache options in the settings should start + with either 'beaker.cache.' or 'cache.'. + + """ + cache_settings = {'regions': []} + for key in settings.keys(): + for prefix in ['beaker.cache.', 'cache.']: + if key.startswith(prefix): + name = key.split(prefix)[1].strip() + cache_settings[name] = settings[key].strip() + + if ('expire' in cache_settings + and isinstance(cache_settings['expire'], basestring) + and cache_settings['expire'].lower() in ['none', 'no']): + cache_settings['expire'] = None + + coerce_cache_params(cache_settings) + + if 'enabled' not in cache_settings: + cache_settings['enabled'] = True + + regions = cache_settings['regions'] + if regions: + for region in regions: + if not region: + continue + + region_settings = { + 'data_dir': cache_settings.get('data_dir'), + 'lock_dir': cache_settings.get('lock_dir'), + 'expire': cache_settings.get('expire', 60), + 'enabled': cache_settings['enabled'], + 'key_length': cache_settings.get('key_length', 250), + 'type': cache_settings.get('type'), + 'url': cache_settings.get('url'), + } + region_prefix = '%s.' % region + region_len = len(region_prefix) + for key in list(cache_settings.keys()): + if key.startswith(region_prefix): + region_settings[key[region_len:]] = cache_settings.pop(key) + + if (isinstance(region_settings['expire'], basestring) + and region_settings['expire'].lower() in ['none', 'no']): + region_settings['expire'] = None + coerce_cache_params(region_settings) + cache.cache_regions[region] = region_settings + + +def includeme(config): + session_factory = session_factory_from_settings(config.registry.settings) + config.set_session_factory(session_factory) + set_cache_regions_from_settings(config.registry.settings) diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py --- a/rhodecode/lib/vcs/backends/base.py +++ b/rhodecode/lib/vcs/backends/base.py @@ -33,6 +33,8 @@ import collections import warnings from zope.cachedescriptors.property import Lazy as LazyProperty +from zope.cachedescriptors.property import CachedProperty + from pyramid import compat from rhodecode.translation import lazy_ugettext @@ -53,6 +55,7 @@ log = logging.getLogger(__name__) FILEMODE_DEFAULT = 0o100644 FILEMODE_EXECUTABLE = 0o100755 +EMPTY_COMMIT_ID = '0' * 40 Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id')) @@ -261,6 +264,7 @@ class BaseRepository(object): EMPTY_COMMIT_ID = '0' * 40 path = None + _commit_ids_ver = 0 def __init__(self, repo_path, config=None, create=False, **kwargs): """ @@ -383,7 +387,7 @@ class BaseRepository(object): return commit.size def is_empty(self): - return not bool(self.commit_ids) + return self._remote.is_empty() @staticmethod def check_url(url, config): @@ -404,6 +408,15 @@ class BaseRepository(object): # COMMITS # ========================================================================== + @CachedProperty('_commit_ids_ver') + def commit_ids(self): + raise NotImplementedError + + def append_commit_id(self, commit_id): + if commit_id not in self.commit_ids: + self._rebuild_cache(self.commit_ids + [commit_id]) + self._commit_ids_ver = time.time() + def get_commit(self, commit_id=None, commit_idx=None, pre_load=None, translate_tag=None): """ Returns instance of `BaseCommit` class. If `commit_id` and `commit_idx` @@ -1094,12 +1107,12 @@ class BaseCommit(object): """ return None - def archive_repo(self, file_path, kind='tgz', subrepos=None, - prefix=None, write_metadata=False, mtime=None): + def archive_repo(self, archive_dest_path, kind='tgz', subrepos=None, + prefix=None, write_metadata=False, mtime=None, archive_at_path='/'): """ Creates an archive containing the contents of the repository. - :param file_path: path to the file which to create the archive. + :param archive_dest_path: path to the file which to create the archive. :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``. :param prefix: name of root directory in archive. Default is repository name and commit's short_id joined with dash: @@ -1107,10 +1120,11 @@ class BaseCommit(object): :param write_metadata: write a metadata file into archive. :param mtime: custom modification time for archive creation, defaults to time.time() if not given. + :param archive_at_path: pack files at this path (default '/') :raise VCSError: If prefix has a problem. """ - allowed_kinds = settings.ARCHIVE_SPECS.keys() + allowed_kinds = [x[0] for x in settings.ARCHIVE_SPECS] if kind not in allowed_kinds: raise ImproperArchiveTypeError( 'Archive kind (%s) not supported use one of %s' % @@ -1118,11 +1132,11 @@ class BaseCommit(object): prefix = self._validate_archive_prefix(prefix) - mtime = mtime or time.mktime(self.date.timetuple()) + mtime = mtime is not None or time.mktime(self.date.timetuple()) file_info = [] cur_rev = self.repository.get_commit(commit_id=self.raw_id) - for _r, _d, files in cur_rev.walk('/'): + for _r, _d, files in cur_rev.walk(archive_at_path): for f in files: f_path = os.path.join(prefix, f.path) file_info.append( @@ -1131,15 +1145,15 @@ class BaseCommit(object): if write_metadata: metadata = [ ('repo_name', self.repository.name), - ('rev', self.raw_id), - ('create_time', mtime), + ('commit_id', self.raw_id), + ('mtime', mtime), ('branch', self.branch), ('tags', ','.join(self.tags)), ] meta = ["%s:%s" % (f_name, value) for f_name, value in metadata] file_info.append(('.archival.txt', 0o644, False, '\n'.join(meta))) - connection.Hg.archive_repo(file_path, mtime, file_info, kind) + connection.Hg.archive_repo(archive_dest_path, mtime, file_info, kind) def _validate_archive_prefix(self, prefix): if prefix is None: @@ -1508,9 +1522,7 @@ class BaseInMemoryCommit(object): "Cannot remove node at %s from " "following parents: %s" % (not_removed, parents)) - def commit( - self, message, author, parents=None, branch=None, date=None, - **kwargs): + def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created :class:`BaseCommit`. Updates repository's @@ -1558,7 +1570,7 @@ class EmptyCommit(BaseCommit): """ def __init__( - self, commit_id='0' * 40, repo=None, alias=None, idx=-1, + self, commit_id=EMPTY_COMMIT_ID, repo=None, alias=None, idx=-1, message='', author='', date=None): self._empty_commit_id = commit_id # TODO: johbo: Solve idx parameter, default value does not make @@ -1618,7 +1630,7 @@ class EmptyChangeset(EmptyCommit): "Use EmptyCommit instead of EmptyChangeset", DeprecationWarning) return super(EmptyCommit, cls).__new__(cls, *args, **kwargs) - def __init__(self, cs='0' * 40, repo=None, requested_revision=None, + def __init__(self, cs=EMPTY_COMMIT_ID, repo=None, requested_revision=None, alias=None, revision=-1, message='', author='', date=None): if requested_revision is not None: warnings.warn( diff --git a/rhodecode/lib/vcs/backends/git/commit.py b/rhodecode/lib/vcs/backends/git/commit.py --- a/rhodecode/lib/vcs/backends/git/commit.py +++ b/rhodecode/lib/vcs/backends/git/commit.py @@ -234,8 +234,7 @@ class GitCommit(base.BaseCommit): path = self._fix_path(path) if self._get_kind(path) != NodeKind.FILE: raise CommitError( - "File does not exist for commit %s at '%s'" % - (self.raw_id, path)) + "File does not exist for commit %s at '%s'" % (self.raw_id, path)) return path def _get_file_nodes(self): @@ -353,8 +352,7 @@ class GitCommit(base.BaseCommit): def get_nodes(self, path): if self._get_kind(path) != NodeKind.DIR: raise CommitError( - "Directory does not exist for commit %s at " - " '%s'" % (self.raw_id, path)) + "Directory does not exist for commit %s at '%s'" % (self.raw_id, path)) path = self._fix_path(path) id_, _ = self._get_id_for_path(path) tree_id = self._remote[id_]['id'] diff --git a/rhodecode/lib/vcs/backends/git/inmemory.py b/rhodecode/lib/vcs/backends/git/inmemory.py --- a/rhodecode/lib/vcs/backends/git/inmemory.py +++ b/rhodecode/lib/vcs/backends/git/inmemory.py @@ -29,8 +29,7 @@ from rhodecode.lib.vcs.backends import b class GitInMemoryCommit(base.BaseInMemoryCommit): - def commit(self, message, author, parents=None, branch=None, date=None, - **kwargs): + def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created `GitCommit`. Updates repository's @@ -94,12 +93,12 @@ class GitInMemoryCommit(base.BaseInMemor commit_data, branch, commit_tree, updated, removed) # Update vcs repository object - self.repository.commit_ids.append(commit_id) - self.repository._rebuild_cache(self.repository.commit_ids) + self.repository.append_commit_id(commit_id) # invalidate parsed refs after commit self.repository._refs = self.repository._get_refs() self.repository.branches = self.repository._get_branches() - tip = self.repository.get_commit() + tip = self.repository.get_commit(commit_id) + self.reset() return tip diff --git a/rhodecode/lib/vcs/backends/git/repository.py b/rhodecode/lib/vcs/backends/git/repository.py --- a/rhodecode/lib/vcs/backends/git/repository.py +++ b/rhodecode/lib/vcs/backends/git/repository.py @@ -25,8 +25,10 @@ GIT repository module import logging import os import re +import time from zope.cachedescriptors.property import Lazy as LazyProperty +from zope.cachedescriptors.property import CachedProperty from rhodecode.lib.compat import OrderedDict from rhodecode.lib.datelib import ( @@ -69,6 +71,9 @@ class GitRepository(BaseRepository): # caches self._commit_ids = {} + # dependent that trigger re-computation of commit_ids + self._commit_ids_ver = 0 + @LazyProperty def _remote(self): return connection.Git(self.path, self.config, with_wire=self.with_wire) @@ -81,7 +86,7 @@ class GitRepository(BaseRepository): def head(self): return self._remote.head() - @LazyProperty + @CachedProperty('_commit_ids_ver') def commit_ids(self): """ Returns list of commit ids, in ascending order. Being lazy @@ -222,13 +227,10 @@ class GitRepository(BaseRepository): return [] return output.splitlines() - def _get_commit_id(self, commit_id_or_idx): + def _lookup_commit(self, commit_id_or_idx, translate_tag=True): def is_null(value): return len(value) == commit_id_or_idx.count('0') - if self.is_empty(): - raise EmptyRepositoryError("There are no commits yet") - if commit_id_or_idx in (None, '', 'tip', 'HEAD', 'head', -1): return self.commit_ids[-1] @@ -238,8 +240,7 @@ class GitRepository(BaseRepository): try: commit_id_or_idx = self.commit_ids[int(commit_id_or_idx)] except Exception: - msg = "Commit %s does not exist for %s" % ( - commit_id_or_idx, self) + msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name) raise CommitDoesNotExistError(msg) elif is_bstr: @@ -261,8 +262,7 @@ class GitRepository(BaseRepository): if (not SHA_PATTERN.match(commit_id_or_idx) or commit_id_or_idx not in self.commit_ids): - msg = "Commit %s does not exist for %s" % ( - commit_id_or_idx, self) + msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name) raise CommitDoesNotExistError(msg) # Ensure we return full id @@ -431,19 +431,42 @@ class GitRepository(BaseRepository): Returns `GitCommit` object representing commit from git repository at the given `commit_id` or head (most recent commit) if None given. """ + if self.is_empty(): + raise EmptyRepositoryError("There are no commits yet") + if commit_id is not None: self._validate_commit_id(commit_id) + try: + # we have cached idx, use it without contacting the remote + idx = self._commit_ids[commit_id] + return GitCommit(self, commit_id, idx, pre_load=pre_load) + except KeyError: + pass + elif commit_idx is not None: self._validate_commit_idx(commit_idx) - commit_id = commit_idx - commit_id = self._get_commit_id(commit_id) + try: + _commit_id = self.commit_ids[commit_idx] + if commit_idx < 0: + commit_idx = self.commit_ids.index(_commit_id) + return GitCommit(self, _commit_id, commit_idx, pre_load=pre_load) + except IndexError: + commit_id = commit_idx + else: + commit_id = "tip" + + commit_id = self._lookup_commit(commit_id) + remote_idx = None + if translate_tag: + # Need to call remote to translate id for tagging scenario + remote_data = self._remote.get_object(commit_id) + commit_id = remote_data["commit_id"] + remote_idx = remote_data["idx"] + try: - if translate_tag: - # Need to call remote to translate id for tagging scenario - commit_id = self._remote.get_object(commit_id)["commit_id"] idx = self._commit_ids[commit_id] except KeyError: - raise RepositoryError("Cannot get object with id %s" % commit_id) + idx = remote_idx or 0 return GitCommit(self, commit_id, idx, pre_load=pre_load) @@ -472,6 +495,7 @@ class GitRepository(BaseRepository): """ if self.is_empty(): raise EmptyRepositoryError("There are no commits yet") + self._validate_branch_name(branch_name) if start_id is not None: @@ -479,9 +503,9 @@ class GitRepository(BaseRepository): if end_id is not None: self._validate_commit_id(end_id) - start_raw_id = self._get_commit_id(start_id) + start_raw_id = self._lookup_commit(start_id) start_pos = self._commit_ids[start_raw_id] if start_id else None - end_raw_id = self._get_commit_id(end_id) + end_raw_id = self._lookup_commit(end_id) end_pos = max(0, self._commit_ids[end_raw_id]) if end_id else None if None not in [start_id, end_id] and start_pos > end_pos: @@ -589,8 +613,9 @@ class GitRepository(BaseRepository): commit = commit.parents[0] self._remote.set_refs('refs/heads/%s' % branch_name, commit.raw_id) - self.commit_ids = self._get_all_commit_ids() - self._rebuild_cache(self.commit_ids) + self._commit_ids_ver = time.time() + # we updated _commit_ids_ver so accessing self.commit_ids will re-compute it + return len(self.commit_ids) def get_common_ancestor(self, commit_id1, commit_id2, repo2): if commit_id1 == commit_id2: diff --git a/rhodecode/lib/vcs/backends/hg/inmemory.py b/rhodecode/lib/vcs/backends/hg/inmemory.py --- a/rhodecode/lib/vcs/backends/hg/inmemory.py +++ b/rhodecode/lib/vcs/backends/hg/inmemory.py @@ -30,8 +30,7 @@ from rhodecode.lib.vcs.exceptions import class MercurialInMemoryCommit(BaseInMemoryCommit): - def commit(self, message, author, parents=None, branch=None, date=None, - **kwargs): + def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created `MercurialCommit`. Updates repository's @@ -83,15 +82,14 @@ class MercurialInMemoryCommit(BaseInMemo date, tz = date_to_timestamp_plus_offset(date) - new_id = self.repository._remote.commitctx( + commit_id = self.repository._remote.commitctx( message=message, parents=parent_ids, commit_time=date, commit_timezone=tz, user=author, files=self.get_paths(), extra=kwargs, removed=removed, updated=updated) + self.repository.append_commit_id(commit_id) - self.repository.commit_ids.append(new_id) - self.repository._rebuild_cache(self.repository.commit_ids) self.repository.branches = self.repository._get_branches() - tip = self.repository.get_commit() + tip = self.repository.get_commit(commit_id) self.reset() return tip diff --git a/rhodecode/lib/vcs/backends/hg/repository.py b/rhodecode/lib/vcs/backends/hg/repository.py --- a/rhodecode/lib/vcs/backends/hg/repository.py +++ b/rhodecode/lib/vcs/backends/hg/repository.py @@ -24,9 +24,11 @@ HG repository module import os import logging import binascii +import time import urllib from zope.cachedescriptors.property import Lazy as LazyProperty +from zope.cachedescriptors.property import CachedProperty from rhodecode.lib.compat import OrderedDict from rhodecode.lib.datelib import ( @@ -85,11 +87,14 @@ class MercurialRepository(BaseRepository # caches self._commit_ids = {} + # dependent that trigger re-computation of commit_ids + self._commit_ids_ver = 0 + @LazyProperty def _remote(self): return connection.Hg(self.path, self.config, with_wire=self.with_wire) - @LazyProperty + @CachedProperty('_commit_ids_ver') def commit_ids(self): """ Returns list of commit ids, in ascending order. Being lazy @@ -157,8 +162,7 @@ class MercurialRepository(BaseRepository return OrderedDict(sorted(_tags, key=get_name, reverse=True)) - def tag(self, name, user, commit_id=None, message=None, date=None, - **kwargs): + def tag(self, name, user, commit_id=None, message=None, date=None, **kwargs): """ Creates and returns a tag for the given ``commit_id``. @@ -172,6 +176,7 @@ class MercurialRepository(BaseRepository """ if name in self.tags: raise TagAlreadyExistError("Tag %s already exists" % name) + commit = self.get_commit(commit_id=commit_id) local = kwargs.setdefault('local', False) @@ -180,8 +185,7 @@ class MercurialRepository(BaseRepository date, tz = date_to_timestamp_plus_offset(date) - self._remote.tag( - name, commit.raw_id, message, local, user, date, tz) + self._remote.tag(name, commit.raw_id, message, local, user, date, tz) self._remote.invalidate_vcs_cache() # Reinitialize tags @@ -203,6 +207,7 @@ class MercurialRepository(BaseRepository """ if name not in self.tags: raise TagDoesNotExistError("Tag %s does not exist" % name) + if message is None: message = "Removed tag %s" % name local = False @@ -271,8 +276,9 @@ class MercurialRepository(BaseRepository self._remote.strip(commit_id, update=False, backup="none") self._remote.invalidate_vcs_cache() - self.commit_ids = self._get_all_commit_ids() - self._rebuild_cache(self.commit_ids) + self._commit_ids_ver = time.time() + # we updated _commit_ids_ver so accessing self.commit_ids will re-compute it + return len(self.commit_ids) def verify(self): verify = self._remote.verify() @@ -425,18 +431,20 @@ class MercurialRepository(BaseRepository if commit_id is not None: self._validate_commit_id(commit_id) try: + # we have cached idx, use it without contacting the remote idx = self._commit_ids[commit_id] return MercurialCommit(self, commit_id, idx, pre_load=pre_load) except KeyError: pass + elif commit_idx is not None: self._validate_commit_idx(commit_idx) try: - id_ = self.commit_ids[commit_idx] + _commit_id = self.commit_ids[commit_idx] if commit_idx < 0: - commit_idx += len(self.commit_ids) - return MercurialCommit( - self, id_, commit_idx, pre_load=pre_load) + commit_idx = self.commit_ids.index(_commit_id) + + return MercurialCommit(self, _commit_id, commit_idx, pre_load=pre_load) except IndexError: commit_id = commit_idx else: @@ -448,8 +456,8 @@ class MercurialRepository(BaseRepository try: raw_id, idx = self._remote.lookup(commit_id, both=True) except CommitDoesNotExistError: - msg = "Commit %s does not exist for %s" % ( - commit_id, self) + msg = "Commit {} does not exist for `{}`".format( + *map(safe_str, [commit_id, self.name])) raise CommitDoesNotExistError(msg) return MercurialCommit(self, raw_id, idx, pre_load=pre_load) @@ -477,11 +485,11 @@ class MercurialRepository(BaseRepository ``end`` could not be found. """ # actually we should check now if it's not an empty repo - branch_ancestors = False if self.is_empty(): raise EmptyRepositoryError("There are no commits yet") self._validate_branch_name(branch_name) + branch_ancestors = False if start_id is not None: self._validate_commit_id(start_id) c_start = self.get_commit(commit_id=start_id) diff --git a/rhodecode/lib/vcs/backends/svn/inmemory.py b/rhodecode/lib/vcs/backends/svn/inmemory.py --- a/rhodecode/lib/vcs/backends/svn/inmemory.py +++ b/rhodecode/lib/vcs/backends/svn/inmemory.py @@ -30,8 +30,7 @@ from rhodecode.lib.vcs.backends import b class SubversionInMemoryCommit(base.BaseInMemoryCommit): - def commit(self, message, author, parents=None, branch=None, date=None, - **kwargs): + def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): if branch not in (None, self.repository.DEFAULT_BRANCH_NAME): raise NotImplementedError("Branches are not yet supported") @@ -74,8 +73,7 @@ class SubversionInMemoryCommit(base.Base # we should not add the commit_id, if it is already evaluated, it # will not be evaluated again. commit_id = str(svn_rev) - if commit_id not in self.repository.commit_ids: - self.repository.commit_ids.append(commit_id) + self.repository.append_commit_id(commit_id) tip = self.repository.get_commit() self.reset() return tip diff --git a/rhodecode/lib/vcs/backends/svn/repository.py b/rhodecode/lib/vcs/backends/svn/repository.py --- a/rhodecode/lib/vcs/backends/svn/repository.py +++ b/rhodecode/lib/vcs/backends/svn/repository.py @@ -27,6 +27,7 @@ import os import urllib from zope.cachedescriptors.property import Lazy as LazyProperty +from zope.cachedescriptors.property import CachedProperty from rhodecode.lib.compat import OrderedDict from rhodecode.lib.datelib import date_astimestamp @@ -75,6 +76,9 @@ class SubversionRepository(base.BaseRepo self._init_repo(create, src_url) + # dependent that trigger re-computation of commit_ids + self._commit_ids_ver = 0 + @LazyProperty def _remote(self): return connection.Svn(self.path, self.config) @@ -93,11 +97,14 @@ class SubversionRepository(base.BaseRepo else: self._check_path() - @LazyProperty + @CachedProperty('_commit_ids_ver') def commit_ids(self): head = self._remote.lookup(None) return [str(r) for r in xrange(1, head + 1)] + def _rebuild_cache(self, commit_ids): + pass + def run_svn_command(self, cmd, **opts): """ Runs given ``cmd`` as svn command and returns tuple @@ -277,7 +284,7 @@ class SubversionRepository(base.BaseRepo try: commit_id = self.commit_ids[commit_idx] except IndexError: - raise CommitDoesNotExistError + raise CommitDoesNotExistError('No commit with idx: {}'.format(commit_idx)) commit_id = self._sanitize_commit_id(commit_id) commit = SubversionCommit(repository=self, commit_id=commit_id) diff --git a/rhodecode/lib/vcs/conf/settings.py b/rhodecode/lib/vcs/conf/settings.py --- a/rhodecode/lib/vcs/conf/settings.py +++ b/rhodecode/lib/vcs/conf/settings.py @@ -42,12 +42,16 @@ BACKENDS = { 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository', } -# TODO: Remove once controllers/files.py is adjusted -ARCHIVE_SPECS = { - 'tbz2': ('application/x-bzip2', '.tar.bz2'), - 'tgz': ('application/x-gzip', '.tar.gz'), - 'zip': ('application/zip', '.zip'), -} + +ARCHIVE_SPECS = [ + ('tbz2', 'application/x-bzip2', 'tbz2'), + ('tbz2', 'application/x-bzip2', '.tar.bz2'), + + ('tgz', 'application/x-gzip', '.tgz'), + ('tgz', 'application/x-gzip', '.tar.gz'), + + ('zip', 'application/zip', '.zip'), +] HOOKS_PROTOCOL = None HOOKS_DIRECT_CALLS = False diff --git a/rhodecode/lib/vcs/utils/helpers.py b/rhodecode/lib/vcs/utils/helpers.py --- a/rhodecode/lib/vcs/utils/helpers.py +++ b/rhodecode/lib/vcs/utils/helpers.py @@ -101,23 +101,35 @@ def parse_datetime(text): :param text: string of desired date/datetime or something more verbose, like *yesterday*, *2weeks 3days*, etc. """ + if not text: + raise ValueError('Wrong date: "%s"' % text) - text = text.strip().lower() + if isinstance(text, datetime.datetime): + return text - INPUT_FORMATS = ( + # we limit a format to no include microseconds e.g 2017-10-17t17:48:23.XXXX + text = text.strip().lower()[:19] + + input_formats = ( '%Y-%m-%d %H:%M:%S', + '%Y-%m-%dt%H:%M:%S', '%Y-%m-%d %H:%M', + '%Y-%m-%dt%H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', + '%m/%d/%Yt%H:%M:%S', '%m/%d/%Y %H:%M', + '%m/%d/%Yt%H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', + '%m/%d/%yt%H:%M:%S', '%m/%d/%y %H:%M', + '%m/%d/%yt%H:%M', '%m/%d/%y', ) - for format in INPUT_FORMATS: + for format_def in input_formats: try: - return datetime.datetime(*time.strptime(text, format)[:6]) + return datetime.datetime(*time.strptime(text, format_def)[:6]) except ValueError: pass diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -59,7 +59,7 @@ from rhodecode.lib.vcs.backends.base imp from rhodecode.lib.utils2 import ( str2bool, safe_str, get_commit_safe, safe_unicode, sha1_safe, time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict, - glob2re, StrictAttributeDict, cleaned_uri) + glob2re, StrictAttributeDict, cleaned_uri, datetime_to_time, OrderedDefaultDict) from rhodecode.lib.jsonalchemy import MutationObj, MutationList, JsonType, \ JsonRaw from rhodecode.lib.ext_json import json @@ -1678,11 +1678,12 @@ class Repository(Base, BaseModel): cascade="all, delete, delete-orphan") ui = relationship('RepoRhodeCodeUi', cascade="all") settings = relationship('RepoRhodeCodeSetting', cascade="all") - integrations = relationship('Integration', - cascade="all, delete, delete-orphan") + integrations = relationship('Integration', cascade="all, delete, delete-orphan") scoped_tokens = relationship('UserApiKeys', cascade="all") + artifacts = relationship('FileStore', cascade="all") + def __unicode__(self): return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, safe_unicode(self.repo_name)) @@ -1730,7 +1731,9 @@ class Repository(Base, BaseModel): from rhodecode.lib.vcs.backends.base import EmptyCommit dummy = EmptyCommit().__json__() if not self._changeset_cache: - return dummy + dummy['source_repo_id'] = self.repo_id + return json.loads(json.dumps(dummy)) + try: return json.loads(self._changeset_cache) except TypeError: @@ -2183,6 +2186,20 @@ class Repository(Base, BaseModel): return make_lock, currently_locked, lock_info @property + def last_commit_cache_update_diff(self): + return time.time() - (safe_int(self.changeset_cache.get('updated_on')) or 0) + + @property + def last_commit_change(self): + from rhodecode.lib.vcs.utils.helpers import parse_datetime + empty_date = datetime.datetime.fromtimestamp(0) + date_latest = self.changeset_cache.get('date', empty_date) + try: + return parse_datetime(date_latest) + except Exception: + return empty_date + + @property def last_db_change(self): return self.updated_on @@ -2275,6 +2292,7 @@ class Repository(Base, BaseModel): """ Update cache of last changeset for repository, keys should be:: + source_repo_id short_id raw_id revision @@ -2282,15 +2300,15 @@ class Repository(Base, BaseModel): message date author - - :param cs_cache: + updated_on + """ from rhodecode.lib.vcs.backends.base import BaseChangeset if cs_cache is None: # use no-cache version here scm_repo = self.scm_instance(cache=False, config=config) - empty = not scm_repo or scm_repo.is_empty() + empty = scm_repo is None or scm_repo.is_empty() if not empty: cs_cache = scm_repo.get_commit( pre_load=["author", "date", "message", "parents"]) @@ -2310,18 +2328,28 @@ class Repository(Base, BaseModel): if is_outdated(cs_cache) or not self.changeset_cache: _default = datetime.datetime.utcnow() last_change = cs_cache.get('date') or _default - if self.updated_on and self.updated_on > last_change: - # we check if last update is newer than the new value - # if yes, we use the current timestamp instead. Imagine you get - # old commit pushed 1y ago, we'd set last update 1y to ago. - last_change = _default - log.debug('updated repo %s with new cs cache %s', - self.repo_name, cs_cache) - self.updated_on = last_change + # we check if last update is newer than the new value + # if yes, we use the current timestamp instead. Imagine you get + # old commit pushed 1y ago, we'd set last update 1y to ago. + last_change_timestamp = datetime_to_time(last_change) + current_timestamp = datetime_to_time(last_change) + if last_change_timestamp > current_timestamp: + cs_cache['date'] = _default + + cs_cache['updated_on'] = time.time() self.changeset_cache = cs_cache Session().add(self) Session().commit() + + log.debug('updated repo %s with new commit cache %s', + self.repo_name, cs_cache) else: + cs_cache = self.changeset_cache + cs_cache['updated_on'] = time.time() + self.changeset_cache = cs_cache + Session().add(self) + Session().commit() + log.debug('Skipping update_commit_cache for repo:`%s` ' 'commit already with latest changes', self.repo_name) @@ -2410,6 +2438,7 @@ class Repository(Base, BaseModel): # control over cache behaviour if cache is None and full_cache and not config: return self._get_instance_cached() + # cache here is sent to the "vcs server" return self._get_instance(cache=bool(cache), config=config) def _get_instance_cached(self): @@ -2438,8 +2467,7 @@ class Repository(Base, BaseModel): else: instance = get_instance_cached(*args) - log.debug( - 'Repo instance fetched in %.3fs', inv_context_manager.compute_time) + log.debug('Repo instance fetched in %.3fs', inv_context_manager.compute_time) return instance def _get_instance(self, cache=True, config=None): @@ -2453,7 +2481,8 @@ class Repository(Base, BaseModel): with_wire=custom_wire, create=False, _vcs_alias=self.repo_type) - + if repo is not None: + repo.count() # cache rebuild return repo def __json__(self): @@ -2489,6 +2518,8 @@ class RepoGroup(Base, BaseModel): created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) personal = Column('personal', Boolean(), nullable=True, unique=None, default=None) + _changeset_cache = Column( + "changeset_cache", LargeBinary(), nullable=True) # JSON data repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') @@ -2513,6 +2544,29 @@ class RepoGroup(Base, BaseModel): self._group_name = value self.group_name_hash = self.hash_repo_group_name(value) + @hybrid_property + def changeset_cache(self): + from rhodecode.lib.vcs.backends.base import EmptyCommit + dummy = EmptyCommit().__json__() + if not self._changeset_cache: + dummy['source_repo_id'] = '' + return json.loads(json.dumps(dummy)) + + try: + return json.loads(self._changeset_cache) + except TypeError: + return dummy + except Exception: + log.error(traceback.format_exc()) + return dummy + + @changeset_cache.setter + def changeset_cache(self, val): + try: + self._changeset_cache = json.dumps(val) + except Exception: + log.error(traceback.format_exc()) + @validates('group_parent_id') def validate_group_parent_id(self, key, val): """ @@ -2608,8 +2662,7 @@ class RepoGroup(Base, BaseModel): return q.all() @property - def parents(self): - parents_recursion_limit = 10 + def parents(self, parents_recursion_limit = 10): groups = [] if self.parent_group is None: return groups @@ -2632,6 +2685,20 @@ class RepoGroup(Base, BaseModel): return groups @property + def last_commit_cache_update_diff(self): + return time.time() - (safe_int(self.changeset_cache.get('updated_on')) or 0) + + @property + def last_commit_change(self): + from rhodecode.lib.vcs.utils.helpers import parse_datetime + empty_date = datetime.datetime.fromtimestamp(0) + date_latest = self.changeset_cache.get('date', empty_date) + try: + return parse_datetime(date_latest) + except Exception: + return empty_date + + @property def last_db_change(self): return self.updated_on @@ -2670,7 +2737,7 @@ class RepoGroup(Base, BaseModel): return cnt + children_count(self) - def _recursive_objects(self, include_repos=True): + def _recursive_objects(self, include_repos=True, include_groups=True): all_ = [] def _get_members(root_gr): @@ -2680,11 +2747,16 @@ class RepoGroup(Base, BaseModel): childs = root_gr.children.all() if childs: for gr in childs: - all_.append(gr) + if include_groups: + all_.append(gr) _get_members(gr) + root_group = [] + if include_groups: + root_group = [self] + _get_members(self) - return [self] + all_ + return root_group + all_ def recursive_groups_and_repos(self): """ @@ -2698,6 +2770,12 @@ class RepoGroup(Base, BaseModel): """ return self._recursive_objects(include_repos=False) + def recursive_repos(self): + """ + Returns all children repositories for this group + """ + return self._recursive_objects(include_groups=False) + def get_new_name(self, group_name): """ returns new full group name based on parent and new name @@ -2708,6 +2786,63 @@ class RepoGroup(Base, BaseModel): self.parent_group else []) return RepoGroup.url_sep().join(path_prefix + [group_name]) + def update_commit_cache(self, config=None): + """ + Update cache of last changeset for newest repository inside this group, keys should be:: + + source_repo_id + short_id + raw_id + revision + parents + message + date + author + + """ + from rhodecode.lib.vcs.utils.helpers import parse_datetime + + def repo_groups_and_repos(): + all_entries = OrderedDefaultDict(list) + + def _get_members(root_gr, pos=0): + + for repo in root_gr.repositories: + all_entries[root_gr].append(repo) + + # fill in all parent positions + for parent_group in root_gr.parents: + all_entries[parent_group].extend(all_entries[root_gr]) + + children_groups = root_gr.children.all() + if children_groups: + for cnt, gr in enumerate(children_groups, 1): + _get_members(gr, pos=pos+cnt) + + _get_members(root_gr=self) + return all_entries + + empty_date = datetime.datetime.fromtimestamp(0) + for repo_group, repos in repo_groups_and_repos().items(): + + latest_repo_cs_cache = {} + for repo in repos: + repo_cs_cache = repo.changeset_cache + date_latest = latest_repo_cs_cache.get('date', empty_date) + date_current = repo_cs_cache.get('date', empty_date) + current_timestamp = datetime_to_time(parse_datetime(date_latest)) + if current_timestamp < datetime_to_time(parse_datetime(date_current)): + latest_repo_cs_cache = repo_cs_cache + latest_repo_cs_cache['source_repo_id'] = repo.repo_id + + latest_repo_cs_cache['updated_on'] = time.time() + repo_group.changeset_cache = latest_repo_cs_cache + Session().add(repo_group) + Session().commit() + + log.debug('updated repo group %s with new commit cache %s', + repo_group.group_name, latest_repo_cs_cache) + def permissions(self, with_admins=True, with_owner=True, expand_from_user_groups=False): """ @@ -4301,9 +4436,9 @@ class Gist(Base, BaseModel): def scm_instance(self, **kwargs): """ - Get explicit Mercurial repository used + Get an instance of VCS Repository + :param kwargs: - :return: """ from rhodecode.model.gist import GistModel full_repo_path = os.path.join(self.base_path(), self.gist_access_id) @@ -4953,8 +5088,8 @@ class FileStore(Base, BaseModel): @classmethod def create(cls, file_uid, filename, file_hash, file_size, file_display_name='', - file_description='', enabled=True, check_acl=True, - user_id=None, scope_repo_id=None, scope_repo_group_id=None): + file_description='', enabled=True, check_acl=True, user_id=None, + scope_user_id=None, scope_repo_id=None, scope_repo_group_id=None): store_entry = FileStore() store_entry.file_uid = file_uid @@ -4968,6 +5103,7 @@ class FileStore(Base, BaseModel): store_entry.enabled = enabled store_entry.user_id = user_id + store_entry.scope_user_id = scope_user_id store_entry.scope_repo_id = scope_repo_id store_entry.scope_repo_group_id = scope_repo_group_id return store_entry diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py --- a/rhodecode/model/pull_request.py +++ b/rhodecode/model/pull_request.py @@ -683,6 +683,7 @@ class PullRequestModel(BaseModel): # source repo source_repo = pull_request.source_repo.scm_instance() + try: source_commit = source_repo.get_commit(commit_id=source_ref_name) except CommitDoesNotExistError: @@ -696,6 +697,7 @@ class PullRequestModel(BaseModel): # target repo target_repo = pull_request.target_repo.scm_instance() + try: target_commit = target_repo.get_commit(commit_id=target_ref_name) except CommitDoesNotExistError: @@ -752,8 +754,8 @@ class PullRequestModel(BaseModel): target_commit.raw_id, source_commit.raw_id, source_repo, merge=True, pre_load=pre_load) - ancestor = target_repo.get_common_ancestor( - target_commit.raw_id, source_commit.raw_id, source_repo) + ancestor = source_repo.get_common_ancestor( + source_commit.raw_id, target_commit.raw_id, target_repo) pull_request.source_ref = '%s:%s:%s' % ( source_ref_type, source_ref_name, source_commit.raw_id) @@ -1337,6 +1339,7 @@ class PullRequestModel(BaseModel): name_or_id = reference.name else: name_or_id = reference.commit_id + refreshed_commit = vcs_repository.get_commit(name_or_id) refreshed_reference = Reference( reference.type, reference.name, refreshed_commit.raw_id) diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py --- a/rhodecode/model/repo.py +++ b/rhodecode/model/repo.py @@ -192,14 +192,14 @@ class RepoModel(BaseModel): return repo_log @classmethod - def update_repoinfo(cls, repositories=None): + def update_commit_cache(cls, repositories=None): if not repositories: repositories = Repository.getAll() for repo in repositories: repo.update_commit_cache() def get_repos_as_dict(self, repo_list=None, admin=False, - super_user_actions=False): + super_user_actions=False, short_name=None): _render = get_current_request().get_partial_renderer( 'rhodecode:templates/data_table/_dt_elements.mako') c = _render.get_call_context() @@ -208,8 +208,12 @@ class RepoModel(BaseModel): return _render('quick_menu', repo_name) def repo_lnk(name, rtype, rstate, private, archived, fork_of): + if short_name is not None: + short_name_var = short_name + else: + short_name_var = not admin return _render('repo_name', name, rtype, rstate, private, archived, fork_of, - short_name=not admin, admin=False) + short_name=short_name_var, admin=False) def last_change(last_change): if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo: @@ -250,8 +254,8 @@ class RepoModel(BaseModel): repo.private, repo.archived, repo.fork), "name_raw": repo.repo_name.lower(), - "last_change": last_change(repo.last_db_change), - "last_change_raw": datetime_to_time(repo.last_db_change), + "last_change": last_change(repo.last_commit_change), + "last_change_raw": datetime_to_time(repo.last_commit_change), "last_changeset": last_rev(repo.repo_name, cs_cache), "last_changeset_raw": cs_cache.get('revision'), diff --git a/rhodecode/model/repo_group.py b/rhodecode/model/repo_group.py --- a/rhodecode/model/repo_group.py +++ b/rhodecode/model/repo_group.py @@ -309,6 +309,10 @@ class RepoGroupModel(BaseModel): # trigger the post hook from rhodecode.lib.hooks_base import log_create_repository_group repo_group = RepoGroup.get_by_group_name(group_name) + + # update repo group commit caches initially + repo_group.update_commit_cache() + log_create_repository_group( created_by=user.username, **repo_group.get_dict()) @@ -686,6 +690,13 @@ class RepoGroupModel(BaseModel): 'revoked permission from usergroup: {} on repogroup: {}'.format( group_name, repo_group), namespace='security.repogroup') + @classmethod + def update_commit_cache(cls, repo_groups=None): + if not repo_groups: + repo_groups = RepoGroup.getAll() + for repo_group in repo_groups: + repo_group.update_commit_cache() + def get_repo_groups_as_dict(self, repo_group_list=None, admin=False, super_user_actions=False): @@ -707,6 +718,11 @@ class RepoGroupModel(BaseModel): (datetime.datetime.now() - datetime.datetime.utcnow()).seconds) return _render("last_change", last_change) + def last_rev(repo_name, cs_cache): + return _render('revision', repo_name, cs_cache.get('revision'), + cs_cache.get('raw_id'), cs_cache.get('author'), + cs_cache.get('message'), cs_cache.get('date')) + def desc(desc, personal): return _render( 'repo_group_desc', desc, personal, c.visual.stylify_metatags) @@ -723,13 +739,15 @@ class RepoGroupModel(BaseModel): repo_group_data = [] for group in repo_group_list: + cs_cache = group.changeset_cache + last_repo_name = cs_cache.get('source_repo_name') row = { "menu": quick_menu(group.group_name), "name": repo_group_lnk(group.group_name), "name_raw": group.group_name, - "last_change": last_change(group.last_db_change), - "last_change_raw": datetime_to_time(group.last_db_change), + "last_change": last_change(group.last_commit_change), + "last_change_raw": datetime_to_time(group.last_commit_change), "last_changeset": "", "last_changeset_raw": "", diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py --- a/rhodecode/model/scm.py +++ b/rhodecode/model/scm.py @@ -818,6 +818,8 @@ class ScmModel(BaseModel): repo_name=repo.repo_name, repo_alias=scm_instance.alias, commit_ids=[tip.raw_id]) + return tip + def delete_nodes(self, user, repo, message, nodes, parent_commit=None, author=None, trigger_push_hook=True): """ diff --git a/rhodecode/public/css/buttons.less b/rhodecode/public/css/buttons.less --- a/rhodecode/public/css/buttons.less +++ b/rhodecode/public/css/buttons.less @@ -14,11 +14,11 @@ input[type="button"] { font-family: @text-light; text-decoration: none; text-shadow: none; - color: @grey4; + color: @grey2; background-color: white; background-image: none; border: none; - .border ( @border-thickness-buttons, @grey4 ); + .border ( @border-thickness-buttons, @grey5 ); .border-radius (@border-radius); cursor: pointer; white-space: nowrap; @@ -26,6 +26,10 @@ input[type="button"] { -moz-transition: background .3s,color .3s; -o-transition: background .3s,color .3s; transition: background .3s,color .3s; + box-shadow: @button-shadow; + -webkit-box-shadow: @button-shadow; + + a { display: block; @@ -44,8 +48,9 @@ input[type="button"] { outline:none; } &:hover { - color: white; - background-color: @grey4; + color: @rcdarkblue; + background-color: @white; + .border ( @border-thickness, @grey4 ); } .icon-remove-sign { @@ -70,26 +75,26 @@ input[type="button"] { .btn-default { - .border ( @border-thickness-buttons, @rcblue ); + border: @border-thickness solid @grey5; background-image: none; - color: @rcblue; + color: @grey2; a { - color: @rcblue; + color: @grey2; } &:hover, &.active { - color: white; - background-color: @rcdarkblue; - .border ( @border-thickness, @rcdarkblue ); + color: @rcdarkblue; + background-color: @white; + .border ( @border-thickness, @grey4 ); a { - color: white; + color: @grey2; } } &:disabled { - .border ( @border-thickness-buttons, @grey4 ); + .border ( @border-thickness-buttons, @grey5 ); background-color: transparent; } } @@ -326,6 +331,7 @@ input[type="submit"] { .border ( @border-thickness-buttons, @rcblue ); background-color: @rcblue; color: white; + opacity: 0.5; } } @@ -416,3 +422,23 @@ input[type="reset"] { } } + +.button-links { + float: left; + display: inline; + margin: 0; + padding-left: 0; + list-style: none; + text-align: right; + + li { + + + } + + li.active { + background-color: @grey6; + .border ( @border-thickness, @grey4 ); + } + +} diff --git a/rhodecode/public/css/code-block.less b/rhodecode/public/css/code-block.less --- a/rhodecode/public/css/code-block.less +++ b/rhodecode/public/css/code-block.less @@ -404,12 +404,9 @@ div.codeblock { // TODO: johbo: Added interim to get rid of the margin around // Select2 widgets. This needs further cleanup. - margin-top: @padding; - overflow: auto; padding: 0px; - border: @border-thickness solid @grey5; - background: @grey6; + border: @border-thickness solid @grey6; .border-radius(@border-radius); #remove_gist { @@ -479,7 +476,7 @@ div.codeblock { } .code-body { - padding: @padding; + padding: 0.8em 1em; background-color: #ffffff; min-width: 100%; box-sizing: border-box; @@ -492,6 +489,21 @@ div.codeblock { height: auto; width: 100%; } + + .markdown-block { + padding: 1em 0; + } + } + + .codeblock-header { + background: @grey7; + height: 36px; + } + + .path { + border-bottom: 1px solid @grey6; + padding: .65em 1em; + height: 18px; } } diff --git a/rhodecode/public/css/codemirror.less b/rhodecode/public/css/codemirror.less --- a/rhodecode/public/css/codemirror.less +++ b/rhodecode/public/css/codemirror.less @@ -27,7 +27,7 @@ .CodeMirror-gutters { border-right: 1px solid #ddd; - background-color: @grey6; + background-color: white; white-space: nowrap; } .CodeMirror-linenumbers {} diff --git a/rhodecode/public/css/comments.less b/rhodecode/public/css/comments.less --- a/rhodecode/public/css/comments.less +++ b/rhodecode/public/css/comments.less @@ -14,7 +14,7 @@ tr.inline-comments div { max-width: 100%; p { - white-space: normal; + white-space: normal; } code, pre, .code, dd { @@ -227,7 +227,7 @@ tr.inline-comments div { .delete-comment { display: inline-block; color: @rcblue; - + &:hover { cursor: pointer; } @@ -377,13 +377,13 @@ form.comment-form { position: relative; width: 100%; min-height: 42px; - + .status_box, .cancel-button { float: left; display: inline-block; } - + .action-buttons { float: right; display: inline-block; @@ -426,10 +426,10 @@ form.comment-form { .comment-form-login { .comment-help { - padding: 0.9em; //same as the button + padding: 0.7em; //same as the button } - div.clearfix { + div.clearfix { clear: both; width: 100%; display: block; diff --git a/rhodecode/public/css/deform.less b/rhodecode/public/css/deform.less --- a/rhodecode/public/css/deform.less +++ b/rhodecode/public/css/deform.less @@ -38,7 +38,7 @@ .form-control { width: 100%; - padding: 0.9em; + padding: 0.7em; border: 1px solid #979797; border-radius: 2px; } diff --git a/rhodecode/public/css/forms.less b/rhodecode/public/css/forms.less --- a/rhodecode/public/css/forms.less +++ b/rhodecode/public/css/forms.less @@ -60,13 +60,13 @@ form.rcform { max-width: 500px; margin: 0 0 @padding -@legend-width; padding: 0 0 0 @legend-width; - + .btn { display: inline-block; margin: 0 1em @padding 0; } } - + input, textarea { float: left; @@ -113,7 +113,7 @@ form.rcform { opacity: 0.5; } } - + input[type="radio"]:not(#ie), input[type="checkbox"]:not(#ie) { // Hide the input, but have it still be clickable @@ -187,13 +187,13 @@ form.rcform { filter: progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476); /* IE6,IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"; /* IE8 */ } - + & + .label { float: left; margin-top: 5px } } - + input[type=checkbox]:not(#ie) { visibility: hidden; &:checked + label:after { @@ -231,6 +231,11 @@ form.rcform { .drop-menu { float: left; + + & + .last-item { + margin: 0; + } + margin: 0 @input-padding 0 0; } @@ -244,7 +249,7 @@ form.rcform { .error-message { margin-top: 5px; } - + input[type=submit] { &:extend(.btn-primary); @@ -271,14 +276,15 @@ form.rcform { .badged-field { .user-badge { line-height: 25px; - padding: 10px 5px; + padding: .4em; border-radius: @border-radius; - border-top: 1px solid @rclightblue; - border-left: 1px solid @rclightblue; - border-bottom: 1px solid @rclightblue; + border-top: 1px solid @grey4; + border-left: 1px solid @grey4; + border-bottom: 1px solid @grey4; font-size: 14px; font-style: normal; color: @text-light; + background: @grey7; display: inline-block; vertical-align: top; cursor: default; diff --git a/rhodecode/public/css/legacy_code_styles.less b/rhodecode/public/css/legacy_code_styles.less --- a/rhodecode/public/css/legacy_code_styles.less +++ b/rhodecode/public/css/legacy_code_styles.less @@ -212,6 +212,13 @@ div.markdown-block strong { margin: 0; } +div.markdown-block ul.checkbox, +div.markdown-block ol.checkbox { + padding-left: 20px !important; + margin-top: 0px !important; + margin-bottom: 18px !important; +} + div.markdown-block ul, div.markdown-block ol { padding-left: 30px !important; @@ -219,6 +226,13 @@ div.markdown-block ol { margin-bottom: 18px !important; } +div.markdown-block ul.checkbox li, +div.markdown-block ol.checkbox li { + list-style: none !important; + margin: 6px !important; + padding: 0 !important; +} + div.markdown-block ul li, div.markdown-block ol li { list-style: disc !important; diff --git a/rhodecode/public/css/login.less b/rhodecode/public/css/login.less --- a/rhodecode/public/css/login.less +++ b/rhodecode/public/css/login.less @@ -95,7 +95,7 @@ margin: 0 1em @padding 0; } } - + .checkbox { display: inline; width: auto; @@ -198,15 +198,16 @@ } .user-menu.submenu { - right: 0; - left: auto; + right: 0!important; + left: auto!important; min-width: 290px; } - .user-menu { .bookmark-items { - padding: 4px 2px; + border-top: @border-thickness solid @grey6; + margin-top: 1em; + padding: 1em .5em; color: @grey3; border-bottom: @grey3; @@ -227,8 +228,10 @@ padding: @menupadding; z-index: 999; overflow: hidden; - background-color: @grey6; + background-color: @white; + border: 1px solid @grey5; color: @grey2; + box-shadow: @dropdown-shadow; h4 { margin-bottom: 12px; @@ -261,7 +264,7 @@ .buttons .register { a { color: @rcblue; - + &:hover { color: @rcdarkblue; } @@ -289,15 +292,16 @@ .big_gravatar { float: left; display: block; - margin-top: .5em; + padding: .5em; } - .full_name, - .email { - margin: 0 0 0 65px; + .full_name { + margin: 0 0 0 70px; + padding-top: 1em; } .email { + margin: 0 0 0 70px; font-family: @text-light; } @@ -307,8 +311,6 @@ padding: @padding 0 0 0; li { - border-top: @border-thickness solid @grey5; - input { margin: @padding 0 0 0; } diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less --- a/rhodecode/public/css/main.less +++ b/rhodecode/public/css/main.less @@ -107,6 +107,12 @@ input + .action-link, .action-link.first .clipboard-action { cursor: pointer; + color: @grey4; + margin-left: 5px; + + &:hover { + color: @grey2; + } } ul.simple-list{ @@ -237,7 +243,7 @@ input.inline[type="file"] { position: relative; vertical-align: bottom; padding: 0 @header-padding; - background-color: @grey2; + background-color: @grey1; color: @grey5; .title { @@ -271,7 +277,9 @@ input.inline[type="file"] { // Gists #files_data { clear: both; //for firefox + padding-top: 10px; } + #gistid { margin-right: @padding; } @@ -516,7 +524,7 @@ ul.auth_plugins { text-align: center; vertical-align: middle; color: @grey2; - background-color: @grey6; + font-size: 11px; p { margin: 0; @@ -605,10 +613,20 @@ button.close { } -input { +input, textarea { &.disabled { opacity: .5; } + + &:hover { + border-color: @grey3; + box-shadow: @button-shadow; + } + + &:focus { + border-color: @rcblue; + box-shadow: @button-shadow; + } } // remove extra padding in firefox @@ -643,16 +661,20 @@ select { padding: 0 18px 0 8px; line-height:1em; font-size: @basefontsize; - border: @border-thickness solid @rcblue; + border: @border-thickness solid @grey5; + border-radius: @border-radius; background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%; - color: @rcblue; + color: @grey4; + box-shadow: @button-shadow; &:after { content: "\00A0\25BE"; } - &:focus { + &:focus, &:hover { outline: none; + border-color: @grey4; + color: @rcdarkblue; } } @@ -712,8 +734,8 @@ label { margin: -5px 0; padding: 0; line-height: 1em; - border: 1px solid @grey4; box-sizing: content-box; + border-radius: 50%; &.gravatar-large { margin: -0.5em .25em -0.5em 0; @@ -938,9 +960,6 @@ label { } -#graph_nodes { - padding-top: 43px; -} #graph_content{ @@ -973,13 +992,12 @@ label { } .graph-col-wrapper { - padding-left: 110px; #graph_nodes { width: 100px; - margin-left: -110px; - float: left; - clear: left; + position: absolute; + left: 70px; + z-index: -1; } } @@ -996,6 +1014,16 @@ label { } } +.obsolete-toggle { + line-height: 30px; + margin-left: -15px; +} + +#rev_range_container, #rev_range_clear, #rev_range_more { + margin-top: -5px; + margin-bottom: -5px; +} + #filter_changelog { float: left; } @@ -1051,7 +1079,7 @@ label { } .flag_status { - margin: 2px 8px 6px 2px; + margin: 2px; &.under_review { .circle(5px, @alert3); } @@ -1222,24 +1250,37 @@ table.integrations { .autocomplete-suggestions { width: auto !important; // overrides autocomplete.js + min-width: 278px; margin: 0; - border: @border-thickness solid @rcblue; + border: @border-thickness solid @grey5; border-radius: @border-radius; - color: @rcblue; + color: @grey2; background-color: white; } + +.autocomplete-qfilter-suggestions { + width: auto !important; // overrides autocomplete.js + max-height: 100% !important; + min-width: 376px; + margin: 0; + border: @border-thickness solid @grey5; + color: @grey2; + background-color: white; +} + .autocomplete-selected { background: #F0F0F0; } + .ac-container-wrap { margin: 0; padding: 8px; - border-bottom: @border-thickness solid @rclightblue; + border-bottom: @border-thickness solid @grey5; list-style-type: none; cursor: pointer; &:hover { - background-color: @rclightblue; + background-color: @grey7; } img { @@ -1294,9 +1335,9 @@ table.integrations { } } - #editor_container{ - position: relative; - margin: @padding; + #editor_container { + position: relative; + margin: @padding 10px; } } @@ -1800,7 +1841,6 @@ BIN_FILENODE = 7 } #changeset_compare_view_content { - margin-bottom: @space; clear: both; width: 100%; box-sizing: border-box; @@ -2031,15 +2071,15 @@ BIN_FILENODE = 7 // Files .edit-file-title { - border-bottom: @border-thickness solid @border-default-color; - - .breadcrumbs { - margin-bottom: 0; + font-size: 16px; + + .title-heading { + padding: 2px; } } .edit-file-fieldset { - margin-top: @sidebarpadding; + margin: @sidebarpadding 0; .fieldset { .left-label { @@ -2084,8 +2124,29 @@ BIN_FILENODE = 7 .new-file, #filter_activate, #filter_deactivate { - float: left; - margin: 0 0 0 15px; + float: right; + margin: 0 0 0 10px; +} + +.file-upload-transaction-wrapper { + margin-top: 57px; + clear: both; +} + +.file-upload-transaction-wrapper .error { + color: @color5; +} + +.file-upload-transaction { + min-height: 200px; + padding: 54px; + border: 1px solid @grey5; + text-align: center; + clear: both; +} + +.file-upload-transaction i { + font-size: 48px } h3.files_location{ @@ -2093,11 +2154,12 @@ h3.files_location{ } .browser-nav { + width: 100%; display: table; - margin-bottom: @space; - + margin-bottom: 20px; .info_box { + float: left; display: inline-table; height: 2.5em; @@ -2106,36 +2168,58 @@ h3.files_location{ vertical-align: middle; } + .drop-menu { + margin: 0 10px; + } + .info_box_elem { - border-top: @border-thickness solid @rcblue; - border-bottom: @border-thickness solid @rcblue; + border-top: @border-thickness solid @grey5; + border-bottom: @border-thickness solid @grey5; + box-shadow: @button-shadow; #at_rev, a { - padding: 0.6em 0.9em; + padding: 0.6em 0.4em; margin: 0; .box-shadow(none); border: 0; height: 12px; + color: @grey2; } input#at_rev { max-width: 50px; - text-align: right; + text-align: center; } &.previous { - border: @border-thickness solid @rcblue; + border: @border-thickness solid @grey5; + border-top-left-radius: @border-radius; + border-bottom-left-radius: @border-radius; + + &:hover { + border-color: @grey4; + } + .disabled { - color: @grey4; + color: @grey5; cursor: not-allowed; + opacity: 0.5; } } &.next { - border: @border-thickness solid @rcblue; + border: @border-thickness solid @grey5; + border-top-right-radius: @border-radius; + border-bottom-right-radius: @border-radius; + + &:hover { + border-color: @grey4; + } + .disabled { - color: @grey4; + color: @grey5; cursor: not-allowed; + opacity: 0.5; } } } @@ -2152,8 +2236,14 @@ h3.files_location{ margin-right: @padding; } } + } + .select-index-number { + margin: 0 0 0 20px; + color: @grey3; + } + .search_activate { display: table-cell; vertical-align: middle; @@ -2182,26 +2272,54 @@ h3.files_location{ margin: -25px 0px 5px 0px; } -.node-filter { - font-size: @repo-title-fontsize; - padding: 4px 0px 0px 0px; - - .node-filter-path { - float: left; - color: @grey4; +.files-quick-filter { + float: right; + width: 180px; + position: relative; +} + +.files-filter-box { + display: flex; + padding: 0px; + border-radius: 3px; + margin-bottom: 0; + + a { + border: none !important; + } + + li { + list-style-type: none + } +} + +.files-filter-box-path { + line-height: 33px; + padding: 0; + width: 20px; + position: absolute; + z-index: 11; + left: 5px; +} + +.files-filter-box-input { + margin-right: 0; + + input { + border: 1px solid @white; + padding-left: 25px; + width: 145px; + + &:hover { + border-color: @grey6; } - .node-filter-input { - float: left; - margin: -2px 0px 0px 2px; - input { - padding: 2px; - border: none; - font-size: @repo-title-fontsize; - } + + &:focus { + border-color: @grey5; } + } } - .browser-result{ td a{ margin-left: 0.5em; @@ -2219,6 +2337,142 @@ h3.files_location{ } +.edit-file-fieldset #location, +.edit-file-fieldset #filename { + display: flex; + width: -moz-available; /* WebKit-based browsers will ignore this. */ + width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */ + width: fill-available; + border: 0; +} + +.path-items { + display: flex; + padding: 0; + border: 1px solid #eeeeee; + width: 100%; + float: left; + + .breadcrumb-path { + line-height: 30px; + padding: 0 4px; + white-space: nowrap; + } + + .location-path { + width: -moz-available; /* WebKit-based browsers will ignore this. */ + width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */ + width: fill-available; + + .file-name-input { + padding: 0.5em 0; + } + + } + + ul { + display: flex; + margin: 0; + padding: 0; + width: 100%; + } + + li { + list-style-type: none; + } + +} + +.editor-items { + height: 40px; + margin: 10px 0 -17px 10px; + + .editor-action { + cursor: pointer; + } + + .editor-action.active { + border-bottom: 2px solid #5C5C5C; + } + + li { + list-style-type: none; + } +} + +.edit-file-fieldset .message textarea { + border: 1px solid #eeeeee; +} + +#files_data .codeblock { + background-color: #F5F5F5; +} + +#editor_preview { + background: white; +} + +.show-editor { + padding: 10px; + background-color: white; + +} + +.show-preview { + padding: 10px; + background-color: white; + border-left: 1px solid #eeeeee; +} +// quick filter +.grid-quick-filter { + float: right; + position: relative; +} + +.grid-filter-box { + display: flex; + padding: 0px; + border-radius: 3px; + margin-bottom: 0; + + a { + border: none !important; + } + + li { + list-style-type: none + } +} + +.grid-filter-box-icon { + line-height: 33px; + padding: 0; + width: 20px; + position: absolute; + z-index: 11; + left: 5px; +} + +.grid-filter-box-input { + margin-right: 0; + + input { + border: 1px solid @white; + padding-left: 25px; + width: 145px; + + &:hover { + border-color: @grey6; + } + + &:focus { + border-color: @grey5; + } + } +} + + + // Search .search-form{ @@ -2281,7 +2535,7 @@ div.search-code-body { } .code-body { - border: @border-thickness solid @border-default-color; + border: @border-thickness solid @grey6; .border-radius(@border-radius); } @@ -2301,6 +2555,11 @@ div.search-code-body { .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; } } + .path { + border-bottom: none !important; + border-left: 1px solid @grey6 !important; + border-right: 1px solid @grey6 !important; + } } table.rctable td.td-search-results div { @@ -2476,3 +2735,56 @@ form.markup-form { padding: 20px; background-color: white; } + + +.dropzone-wrapper { + border: 1px solid @grey5; + padding: 20px; +} + +.dropzone, +.dropzone-pure { + border: 2px dashed @grey5; + border-radius: 5px; + background: white; + min-height: 200px; + padding: 54px; + + .dz-message { + font-weight: 700; + text-align: center; + margin: 2em 0; + } + +} + +.dz-preview { + margin: 10px 0 !important; + position: relative; + vertical-align: top; + padding: 10px; + border-bottom: 1px solid @grey5; +} + +.dz-filename { + font-weight: 700; + float:left; +} + +.dz-sending { + float: right; +} + +.dz-response { + clear:both +} + +.dz-filename-size { + float:right +} + +.dz-error-message { + color: @alert2; + padding-top: 10px; + clear: both; +} diff --git a/rhodecode/public/css/navigation.less b/rhodecode/public/css/navigation.less --- a/rhodecode/public/css/navigation.less +++ b/rhodecode/public/css/navigation.less @@ -2,10 +2,21 @@ // For use in RhodeCode applications; // see style guide documentation for guidelines. +// TOP MAIN DARK NAVIGATION + +.header .main_nav.horizontal-list { + float: right; + color: @grey4; + > li { + a { + color: @grey4; + } + } +} + // HEADER NAVIGATION .horizontal-list { - float: right; display: block; margin: 0; padding: 0; @@ -18,6 +29,7 @@ li { line-height: 1em; list-style-type: none; + margin: 0 20px 0 0; a { padding: 0 .5em; @@ -55,12 +67,6 @@ .user { padding-bottom: 10px; } - - &.open { - .user { - border-bottom: 5px solid @rcblue; - } - } } &:before { content: none; } @@ -80,10 +86,6 @@ } } - &.active { - border-bottom: 5px solid @rcblue; - } - &.open { a { @@ -118,14 +120,12 @@ > a, &.has_select2 a { display: block; - padding: 10px 0 2px; + padding: 10px 0; } .menulabel { - padding: 0 .5em; line-height: 1em; // for this specifically we do not use a variable - border-right: 1px solid @grey4; } .pr_notifications { @@ -141,7 +141,7 @@ &.open, &.active { a { - color: @grey1; + color: @rcblue; } } } @@ -156,6 +156,14 @@ position: relative; } + .menulink { + &.disabled { + color: @grey3; + cursor: default; + opacity: 0.5; + } + } + #quick_login { li a { @@ -281,16 +289,19 @@ } .navigation li:last-child .submenu { - right: -20px; - left: auto; + right: auto; + left: 0; + border: 1px solid @grey5; + background: @white; + box-shadow: @dropdown-shadow; } .submenu { position: absolute; top: 100%; left: 0; - min-width: 150px; - margin: 6px 0 0; + min-width: 180px; + margin: 2px 0 0; padding: 0; text-align: left; font-family: @text-light; @@ -303,7 +314,7 @@ padding: 0 .5em; line-height: 1em; color: @grey3; - background-color: @grey6; + background-color: @white; list-style-type: none; a { @@ -324,7 +335,7 @@ z-index: 30; } &:hover { - background-color: @grey5; + background-color: @grey7; -webkit-transition: background .3s; -moz-transition: background .3s; -o-transition: background .3s; @@ -501,10 +512,10 @@ #context-bar { display: block; - margin: 0 auto; + margin: 0 auto 20px 0; padding: 0 @header-padding; - background-color: @grey6; - border-bottom: @border-thickness solid @grey5; + background-color: @grey7; + border-bottom: 1px solid @grey5; .clear { clear: both; @@ -513,19 +524,22 @@ ul#context-pages { li { - line-height: 1em; list-style-type: none; a { - color: @grey3; + color: @grey2; + + &:hover { + color: @grey1; + } } &.active { // special case, non-variable color - border-bottom: 4px solid @nav-grey; + border-bottom: 2px solid @rcblue; a { - color: @grey1; + color: @rcblue; } } } @@ -534,8 +548,9 @@ ul#context-pages { // PAGINATION .pagination { - border: @border-thickness solid @rcblue; - color: @rcblue; + border: @border-thickness solid @grey5; + color: @grey2; + box-shadow: @button-shadow; .current { color: @grey4; @@ -552,33 +567,44 @@ ul#context-pages { .dataTables_paginate, .pagination-wh { text-align: left; display: inline-block; - border-left: 1px solid @rcblue; + border-left: 1px solid @grey5; float: none; overflow: hidden; + box-shadow: @button-shadow; .paginate_button, .pager_curpage, .pager_link, .pg-previous, .pg-next, .pager_dotdot { display: inline-block; padding: @menupadding/4 @menupadding; - border: 1px solid @rcblue; + border: 1px solid @grey5; border-left: 0; - color: @rcblue; + color: @grey2; cursor: pointer; float: left; + + &:hover { + color: @rcdarkblue; + } } - .pager_curpage, .pager_dotdot, - .paginate_button.current, .paginate_button.disabled, + .paginate_button.disabled, .disabled { color: @grey3; cursor: default; + opacity: 0.5; + } + + .paginate_button.current, .pager_curpage { + background: @rcblue; + border-color: @rcblue; + color: @white; } .ellipsis { display: inline-block; text-align: left; padding: @menupadding/4 @menupadding; - border: 1px solid @rcblue; + border: 1px solid @grey5; border-left: 0; float: left; } @@ -595,14 +621,6 @@ ul#context-pages { font-family: @text-regular; color: @grey1; - &#graph_nodes { - clear:both; - width: auto; - margin-left: -100px; - padding: 0; - border: none; - } - .nav-pills { margin: 0; } @@ -631,14 +649,11 @@ ul#context-pages { .main_filter_help_box { padding: 7px 7px; - border-top: 1px solid @grey4; - border-right: 1px solid @grey4; - border-bottom: 1px solid @grey4; display: inline-block; vertical-align: top; background: inherit; position: absolute; - right: 8px; + right: 0; top: 9px; } @@ -647,8 +662,10 @@ ul#context-pages { .searchItems { display:flex; - background: #666666; + background: @black; padding: 0px; + border-radius: 3px; + border: 1px solid @black; a { border: none !important; @@ -657,26 +674,30 @@ ul#context-pages { .searchTag { line-height: 28px; - padding: 0px 4px; + padding: 0 5px; .tag { - color: @nav-grey; - border-color: @nav-grey; + color: @grey5; + border-color: @grey2; + background: @grey1; } } .searchTagFilter { - background-color: @grey3 !important; + background-color: @black !important; + margin-right: 0; } .searchTagHelp { - background-color: @grey2 !important; + background-color: @grey1 !important; + margin: 0; } .searchTagHelp:hover { - background-color: @grey2 !important; + background-color: @grey1 !important; } .searchTagInput { - background-color: @grey3 !important; + background-color: @grey1 !important; + margin-right: 0; } } @@ -685,32 +706,33 @@ ul#context-pages { } #main_filter_help { - background: @grey3; + background: @grey1; border: 1px solid black; position: absolute; white-space: pre; z-index: 9999; color: @nav-grey; - margin: 1px 7px; padding: 0 10px; } -.main_filter_input { - padding: 5px; - min-width: 260px; - color: @nav-grey; - background: @grey3; - min-height: 18px; - border:none; - border-radius: 0; +input { - &:active { - color: @grey2 !important; - background: white !important; - } - &:focus { - color: @grey2 !important; - background: white !important; + &.main_filter_input { + padding: 5px 10px; + min-width: 340px; + color: @grey7; + background: @black; + min-height: 18px; + border: 0; + + &:active { + color: @grey2 !important; + background: white !important; + } + &:focus { + color: @grey2 !important; + background: white !important; + } } } diff --git a/rhodecode/public/css/panels.less b/rhodecode/public/css/panels.less --- a/rhodecode/public/css/panels.less +++ b/rhodecode/public/css/panels.less @@ -47,7 +47,7 @@ min-height: 150px } } - + .panel-footer { background-color: white; padding: .65em @panel-padding .5em; @@ -63,10 +63,6 @@ &.user-profile { float: left; - .panel-heading { - margin-bottom: @padding; - } - .panel-body { &:extend(.clearfix); } diff --git a/rhodecode/public/css/rcicons.less b/rhodecode/public/css/rcicons.less --- a/rhodecode/public/css/rcicons.less +++ b/rhodecode/public/css/rcicons.less @@ -1,11 +1,13 @@ @font-face { font-family: 'rcicons'; - src: url('../fonts/RCIcons/rcicons.eot?74666722'); - src: url('../fonts/RCIcons/rcicons.eot?74666722#iefix') format('embedded-opentype'), - url('../fonts/RCIcons/rcicons.woff2?74666722') format('woff2'), - url('../fonts/RCIcons/rcicons.woff?74666722') format('woff'), - url('../fonts/RCIcons/rcicons.ttf?74666722') format('truetype'), - url('../fonts/RCIcons/rcicons.svg?74666722#rcicons') format('svg'); + + src: url('../fonts/RCIcons/rcicons.eot?92789106'); + src: url('../fonts/RCIcons/rcicons.eot?92789106#iefix') format('embedded-opentype'), + url('../fonts/RCIcons/rcicons.woff2?92789106') format('woff2'), + url('../fonts/RCIcons/rcicons.woff?92789106') format('woff'), + url('../fonts/RCIcons/rcicons.ttf?92789106') format('truetype'), + url('../fonts/RCIcons/rcicons.svg?92789106#rcicons') format('svg'); + font-weight: normal; font-style: normal; } @@ -55,78 +57,164 @@ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } +.animate-spin { + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; + display: inline-block; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + + + .icon-no-margin::before { margin: 0; } // -- ICON CLASSES -- // +// sorter = lambda s: '\n'.join(sorted(s.splitlines())) +.icon-delete:before { content: '\e800'; } /* '' */ +.icon-ok:before { content: '\e801'; } /* '' */ +.icon-comment:before { content: '\e802'; } /* '' */ .icon-bookmark:before { content: '\e803'; } /* '' */ .icon-branch:before { content: '\e804'; } /* '' */ +.icon-tag:before { content: '\e805'; } /* '' */ .icon-lock:before { content: '\e806'; } /* '' */ .icon-unlock:before { content: '\e807'; } /* '' */ -.icon-delete:before { content: '\e808'; } /* '' */ -.icon-false:before { content: '\e808'; } /* '' */ - -.icon-ok:before { content: '\e809'; } /* '' */ -.icon-true:before { content: '\e809'; } /* '' */ - -.icon-comment:before { content: '\e80a'; } /* '' */ -.icon-comment-add:before { content: '\e816'; } /* '' */ -.icon-comment_toggle:before { content: '\e818'; } /* '' */ - -.icon-feed:before { content: '\e80b'; } /* '' */ - -.icon-right:before { content: '\e80c'; } /* '' */ -.icon-left:before { content: '\e80d'; } /* '' */ - -.icon-arrow_down:before { content: '\e80e'; } /* '' */ -.icon-arrow_up:before { content: '\e80e'; } /* '' */ - -.icon-group:before { content: '\e812'; } /* '' */ - -.icon-fork:before { content: '\e814'; } /* '' */ -.icon-merge:before { content: '\e814'; } /* '' */ - -.icon-more:before { content: '\e815'; } /* '' */ - -.icon-more-linked { cursor: pointer; color: @grey3 } -.icon-more-linked:before { content: '\e815'; } /* '' */ - -.icon-expand-linked { cursor: pointer; color: @grey3; font-size: 8px } -.icon-expand-linked:before { content: '\e80e'; } /* '' */ - -.icon-git-inv:before { content: '\e80f'; } /* '' */ -.icon-hg-inv:before { content: '\e810'; } /* '' */ -.icon-svn-inv:before { content: '\e811'; } /* '' */ - -.icon-git:before { content: '\e81a'; } /* '' */ -.icon-hg:before { content: '\e81b'; } /* '' */ -.icon-svn:before { content: '\e820'; } /* '' */ - -.icon-minus:before { content: '\e81c'; } /* '' */ +.icon-feed:before { content: '\e808'; } /* '' */ +.icon-left:before { content: '\e809'; } /* '' */ +.icon-right:before { content: '\e80a'; } /* '' */ +.icon-down:before { content: '\e80b'; } /* '' */ +.icon-folder:before { content: '\e80c'; } /* '' */ +.icon-folder-open:before { content: '\e80d'; } /* '' */ +.icon-folder-empty:before { content: '\f114'; } /* '' */ +.icon-folder-open-empty:before { content: '\f115'; } /* '' */ +.icon-trash-empty:before { content: '\e80e'; } /* '' */ +.icon-group:before { content: '\e80f'; } /* '' */ +.icon-remove:before { content: '\e810'; } /* '' */ +.icon-fork:before { content: '\e811'; } /* '' */ +.icon-more:before { content: '\e812'; } /* '' */ +.icon-search:before { content: '\e813'; } /* '' */ +.icon-scissors:before { content: '\e814'; } /* '' */ +.icon-download:before { content: '\e815'; } /* '' */ +.icon-doc:before { content: '\e816'; } /* '' */ +.icon-cog:before { content: '\e817'; } /* '' */ +.icon-cog-alt:before { content: '\e818'; } /* '' */ +.icon-eye:before { content: '\e819'; } /* '' */ +.icon-eye-off:before { content: '\e81a'; } /* '' */ +.icon-cancel-circled2:before { content: '\e81b'; } /* '' */ +.icon-cancel-circled:before { content: '\e81c'; } /* '' */ .icon-plus:before { content: '\e81d'; } /* '' */ -.icon-remove:before { content: '\e81e'; } /* '' */ -.icon-remove-sign:before { content: '\e81e'; } /* '' */ - -.icon-rhodecode:before { content: '\e81f'; } /* '' */ - -.icon-tag:before { content: '\e821'; } /* '' */ -.icon-copy:before { content: '\f0c5'; } /* '' */ -.icon-clipboard:before { content: '\f0c5'; } /* '' */ +.icon-plus-circled:before { content: '\e81e'; } /* '' */ +.icon-minus-circled:before { content: '\e81f'; } /* '' */ +.icon-minus:before { content: '\e820'; } /* '' */ +.icon-info-circled:before { content: '\e821'; } /* '' */ +.icon-upload:before { content: '\e822'; } /* '' */ +.icon-home:before { content: '\e823'; } /* '' */ +.icon-git:before { content: '\e82a'; } /* '' */ +.icon-hg:before { content: '\e82d'; } /* '' */ +.icon-svn:before { content: '\e82e'; } /* '' */ +.icon-comment-add:before { content: '\e82f'; } /* '' */ +.icon-comment-toggle:before { content: '\e830'; } /* '' */ +.icon-rhodecode:before { content: '\e831'; } /* '' */ +.icon-up:before { content: '\e832'; } /* '' */ +.icon-merge:before { content: '\e833'; } /* '' */ +.icon-docs:before { content: '\f0c5'; } /* '' */ +.icon-menu:before { content: '\f0c9'; } /* '' */ +.icon-paste:before { content: '\f0ea'; } /* '' */ +.icon-doc-text:before { content: '\f0f6'; } /* '' */ +.icon-plus-squared:before { content: '\f0fe'; } /* '' */ +.icon-minus-squared:before { content: '\f146'; } /* '' */ +.icon-minus-squared-alt:before { content: '\f147'; } /* '' */ +.icon-doc-inv:before { content: '\f15b'; } /* '' */ +.icon-doc-text-inv:before { content: '\f15c'; } /* '' */ +.icon-plus-squared-alt:before { content: '\f196'; } /* '' */ +.icon-file-code:before { content: '\f1c9'; } /* '' */ +.icon-history:before { content: '\f1da'; } /* '' */ +.icon-sliders:before { content: '\f1de'; } /* '' */ +.icon-trash:before { content: '\f1f8'; } /* '' */ +.icon-spin-alt:before { content: '\e834'; } /* '' */ +.icon-spin:before { content: '\e838'; } /* '' */ -.icon-folder:before { content: '\e813'; } /* '' */ -.icon-folder-close:before { content: '\e813'; } /* '' */ - -.icon-directory:before { content: '\e800'; } /* '' */ -.icon-directory-empty:before { content: '\f114'; } /* '' */ -.icon-file-text:before { content: '\f0f6'; } /* '' */ -.icon-file-text-inv:before { content: '\f15c'; } /* '' */ -.icon-file-code:before { content: '\f1c9'; } /* '' */ - -// MERGED ICONS - +// MERGED ICONS BASED ON CURRENT ONES +.icon-repo-group:before { &:extend(.icon-folder-open:before); } .icon-repo-private:before { &:extend(.icon-lock:before); } .icon-repo-lock:before { &:extend(.icon-lock:before); } .icon-unlock-alt:before { &:extend(.icon-unlock:before); } @@ -134,9 +222,20 @@ .icon-repo-public:before { &:extend(.icon-unlock:before); } .icon-rss-sign:before { &:extend(.icon-feed:before); } .icon-code-fork:before { &:extend(.icon-fork:before); } +.icon-arrow_up:before { &:extend(.icon-up:before); } +.icon-file:before { &:extend(.icon-file-code:before); } +.icon-file-text:before { &:extend(.icon-file-code:before); } +.icon-directory:before { &:extend(.icon-folder:before); } +.icon-more-linked:before { &:extend(.icon-more:before); } +.icon-clipboard:before { &:extend(.icon-docs:before); } +.icon-copy:before { &:extend(.icon-docs:before); } +.icon-true:before { &:extend(.icon-ok:before); } +.icon-false:before { &:extend(.icon-delete:before); } +.icon-expand-linked:before { &:extend(.icon-down:before); } +.icon-pr-merge-fail:before { &:extend(.icon-delete:before); } // TRANSFORM -.icon-arrow_up:before {transform: rotate(180deg);} + .icon-merge:before {transform: rotate(180deg);} // -- END ICON CLASSES -- // @@ -152,6 +251,9 @@ .icon-svn-inv { color: @color1 !important; } .icon-repo-lock { color: #FF0000; } .icon-repo-unlock { color: #FF0000; } +.icon-false { color: @grey5 } +.icon-expand-linked { cursor: pointer; color: @grey3; font-size: 14px } +.icon-more-linked { cursor: pointer; color: @grey3 } .repo-switcher-dropdown .select2-result-label { .icon-git:before { diff --git a/rhodecode/public/css/readme-box.less b/rhodecode/public/css/readme-box.less --- a/rhodecode/public/css/readme-box.less +++ b/rhodecode/public/css/readme-box.less @@ -88,7 +88,6 @@ div.readme_box pre { font-size: 13px !important; overflow: visible !important; line-height: 140% !important; - background-color: @grey7; } div.readme_box img { @@ -156,10 +155,10 @@ div.readme_box code { } div.readme_box pre { - border: @border-thickness solid @grey5; + border: @border-thickness solid #CBDBEB; overflow: auto; padding: .5em; - background-color: @grey7; + background-color: #FCFEFF; } div.readme_box pre > code { diff --git a/rhodecode/public/css/select2.less b/rhodecode/public/css/select2.less --- a/rhodecode/public/css/select2.less +++ b/rhodecode/public/css/select2.less @@ -17,7 +17,7 @@ .select2-search, .select2-search input {.box-sizing(border-box);} .select2-container .select2-choice{display:block; line-height:1em; -webkit-touch-callout:none;-moz-user-select:none;-ms-user-select:none;user-select:none; } -.main .select2-container .select2-choice { background-color: white; } +.main .select2-container .select2-choice { background-color: white; box-shadow: @button-shadow;} .select2-container .select2-choice abbr { display: none; width: 12px; height: 12px; position: absolute; right: 24px; top: 8px; font-size: 1px; text-decoration: none; border: 0; background: url('../images/select2.png') right top no-repeat; cursor: pointer; outline: 0; } .select2-container.select2-allowclear .select2-choice abbr {display: inline-block;} .select2-container .select2-choice abbr:hover { background-position: right -11px; cursor: pointer; } @@ -92,10 +92,18 @@ select.select2{height:28px;visibility:hi min-width: 160px; margin: 0 @padding 0 0; padding: 0; - border: @border-thickness solid @rcblue; + border: @border-thickness solid @grey5; border-radius: @border-radius; - color: @rcblue; + color: @grey2; background-color: white; + + a { + color: @grey2; + + &:hover { + color: @rcdarkblue; + } + } } .drop-menu-dropdown { @@ -120,7 +128,7 @@ select.select2{height:28px;visibility:hi a { display:block; - padding: .9em; + padding: .7em; padding-right: 2em; position: relative; @@ -129,7 +137,7 @@ select.select2{height:28px;visibility:hi content: "\00A0\25BE"; right: .1em; line-height: 1em; - top: 0.4em; + top: 0.2em; width: 1em; font-size: 20px; } @@ -157,6 +165,12 @@ select.select2{height:28px;visibility:hi width: 100%; margin: .5em 0; padding: .5em; + border-color: @grey4; + + &:focus, &:hover { + border-color: @rcblue; + box-shadow: @button-shadow; + } } .select2-no-results { @@ -176,7 +190,13 @@ select.select2{height:28px;visibility:hi &:hover, &.select2-highlighted { - background-color: @rclightblue; + background-color: @grey7; + + .select2-result-label { + &:hover { + color: @grey1!important; + } + } } &.select2-result-with-children { @@ -189,8 +209,7 @@ select.select2{height:28px;visibility:hi display:block; padding: 8px; font-family: @text-regular; - border-bottom: @border-thickness solid @rclightblue; - color: @rcblue; + color: @grey2; cursor: pointer; } &.select2-result-with-children { @@ -205,7 +224,7 @@ select.select2{height:28px;visibility:hi ul.select2-result-sub li .select2-result-label { padding-left: 16px; font-family: @text-regular; - color: @rcblue; + color: @grey2; cursor: pointer; } } diff --git a/rhodecode/public/css/summary.less b/rhodecode/public/css/summary.less --- a/rhodecode/public/css/summary.less +++ b/rhodecode/public/css/summary.less @@ -3,30 +3,33 @@ // Used for headers and file detail summary screens. .summary { - float: left; + clear: both; + float: none; position: relative; width: 100%; margin: 0; padding: 0; + background: #FCFCFC; + border: 1px solid #EAEAEA; + border-radius: @border-radius; + margin-bottom: 20px; .summary-detail-header { - float: left; display: block; width: 100%; - margin-bottom: @textmargin; + margin-bottom: 10px; padding: 0 0 .5em 0; border-bottom: @border-thickness solid @border-default-color; .breadcrumbs { - float: left; display: inline; margin: 0; padding: 0; } + h4 { - float: left; margin: 0 1em 0 0; - padding: 0; + padding: 10px 0 5px 20px; line-height: 1.2em; font-size: @basefontsize; } @@ -42,11 +45,11 @@ } .summary-detail { - float: left; + float: none; position: relative; - width: 73%; - margin: 0 3% @space 0; - padding: 0; + width: 100%; + margin: 0; + padding: 0 0 20px 0; .file_diff_buttons { margin-top: @space; @@ -62,18 +65,37 @@ height: 30px; margin: 0; padding: 0; + width: 130px; font-weight: @text-semibold-weight; font-family: @text-semibold; } + .left-clone select { + width: 130px; + margin-right: 0; + background-color: @grey7; + border-color: @grey4; + color: #5C5C5C; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } .right-clone { - float: right; - width: 83%; + float: left; + width: ~"calc(100% - 170px)"; + + .clipboard-action { + margin-left: -30px; + } } .clone_url_input { - width: ~"calc(100% - 35px)"; - padding: 5px; + width: ~"calc(100% - 90px)"; + padding: 6px 30px 6px 10px; + height: 14px; + box-shadow: 0 1px 1px 0 rgba(0,0,0,0.07); + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin-left: -1px; } &.directory { @@ -123,18 +145,32 @@ border: @border-thickness solid @border-default-color; .border-radius(@border-radius); } + + .btn-collapse { + clear: both; + float: none; + background: #F7F7F7; + text-align: center; + color: #949494; + font-size: 11px; + + &:hover { + background: #f1f1f1; + color: #2B2B2D; + } + } } // this is used outside of just the summary .fieldset, // similar to form fieldset .summary .sidebar-right-content { // these have to match clear: both; - float: left; + float: none; position: relative; display:block; width: 100%; - min-height: 1em; - margin-bottom: @textmargin; + min-height: 20px; + margin-bottom: 10px; padding: 0; line-height: 1.2em; @@ -147,19 +183,28 @@ } .summary .sidebar-right-content { - margin-bottom: @space; + margin-bottom: 0; .rc-user { min-width: 0; } + + li { + list-style: none; + line-height: normal; + } +} + +.summary { + .fieldset { + margin-bottom: 0; + } } .fieldset { .left-label { // similar to form legend - float: left; display: block; - width: 25%; margin: 0; padding: 0; font-weight: @text-semibold-weight; @@ -167,16 +212,78 @@ } .left-label-summary { - .left-label; - width: 150px; + padding-left: 20px; + margin-bottom: 5px; + + p { + margin-bottom: 5px; + color: @grey1; + float: left; + width: 130px; + + &.spacing { + margin-top: 10px; + } + } + + .right-label-summary { + float: left; + margin-top: 7px; + width: ~"calc(100% - 160px)"; + } } - + + .left-label-summary-files { + padding-left: 45px; + margin-top: 5px; + + p { + margin-bottom: 5px; + color: @grey1; + float: left; + width: 130px; + + &.spacing { + margin-top: 10px; + } + } + + .right-label-summary { + float: left; + margin-top: 7px; + } + } + + .left-content { + width: ~"calc(60% - 20px)"; + float: left; + margin: 15px 0 15px 20px; + + .rc-user { + min-width: auto; + max-width: none; + min-height: auto; + padding-right: 5px; + } + + .left-content-avatar { + width: 45px; + float: left; + margin-top: 8px; + } + + .left-content-message { + float: left; + width: ~"calc(100% - 45px)"; + } + } + .right-content { // similar to form fields float: left; display: block; - width: 75%; - margin: 0 0 0 -15%; - padding: 0 0 0 15%; + width: ~"calc(40% - 20px)"; + text-align: right; + margin: 15px 20px 15px 0; .truncate-wrap, .truncate { @@ -187,11 +294,49 @@ .commit-long { overflow-x: auto; } + + .commit-info { + margin-top: 7px; + } + + .summary-tag, + .summary-tagtag, + .summary-branchtag, + .summary-booktag, + .summary-metatag, + .summary-perm_tag { + background:transparent; + border: none; + box-shadow: none; + margin-left: 10px; + font-size: 13px; + } + + .summary-tag span, + .summary-tag i, + .summary-tag a { + color: @grey1; + } + + } + .commit { + color: @grey1; + margin-bottom: 5px; + white-space: pre; } .commit.truncate-wrap { overflow:hidden; text-overflow: ellipsis; } + .commit-author { + color: @grey1; + } + .commit-date { + color: @grey4; + } + .fieldset-text-line { + line-height: 36px; + } } // expand commit message @@ -214,19 +359,46 @@ .comments-show { display: inline; } .comments-hide { display: none; } - + &.comments-visible { .comments-show { display: none; } .comments-hide { display: inline; } } } - + // Quick Start section + +.empty-repo { + border: 1px solid #EAEAEA; + border-bottom: 0; + border-radius: @border-radius; + padding: 0 20px; +} + +.empty-repo h3, .quick_start p { + margin-bottom: 10px; +} + +.quick_start pre { + background: #FCFEFF; + border: 1px solid #CBDBEB; + box-shadow: @button-shadow; + padding: 10px 15px; + border-radius: 4px; + color: @grey2; +} + +.clear-fix { + clear: both; +} + .quick_start { - float: left; display: block; position: relative; - width: 100%; + border: 1px solid #EAEAEA; + border-top: 0; + border-radius: @border-radius; + padding: 0 20px; // adds some space to make copy and paste easier .left-label, @@ -235,6 +407,7 @@ } } + .submodule { .summary-detail { width: 100%; @@ -250,23 +423,32 @@ display: block; width: 100%; margin: 0; - padding: @space 0 10px 0; - border-top: @border-thickness solid @border-default-color; + + .file-filename { + float:left; + padding: 10px; + } - .stats { - float: left; + .file-stats { + padding: 10px; + float:right; } - .stats-filename { - font-size: 120%; - } + + .stats-first-item { padding: 0px 0px 0px 3px; } + .stats-info { + font-size: 11px; + color: @grey4; + } + .buttons { float: right; text-align: right; color: @grey4; + padding: 10px; } .file-container { @@ -286,6 +468,25 @@ .repo-size { margin-bottom: .5em; } - + } +.rctable.repo_summary { + border: 1px solid #eaeaea; + border-radius: 2px; + border-collapse: inherit; + border-bottom: 0; + + th { + background: @grey7; + border-bottom: 0; + } + + td { + border-color: #eaeaea; + } + + td.td-status { + padding: 0 0 0 10px; + } +} diff --git a/rhodecode/public/css/tables.less b/rhodecode/public/css/tables.less --- a/rhodecode/public/css/tables.less +++ b/rhodecode/public/css/tables.less @@ -33,7 +33,7 @@ table.dataTable { td { height: auto; max-width: 20%; - padding: .65em 1em .65em 0; + padding: .65em 0 .65em 1em; vertical-align: middle; border-bottom: @border-thickness solid @grey5; white-space: normal; @@ -103,6 +103,11 @@ table.dataTable { } } + &.td-icon { + min-width: 20px; + width: 20px; + } + &.td-hash { min-width: 80px; width: 200px; @@ -113,6 +118,12 @@ table.dataTable { } } + &.td-graphbox { + width: 100px; + max-width: 100px; + min-width: 100px; + } + &.td-time { width: 160px; white-space: nowrap; @@ -408,29 +419,11 @@ table.trending_language_tbl { .trending_language { position: relative; - width: 100%; - height: 19px; overflow: hidden; - background-color: @grey6; + color: @text-color; + width: 400px; - span, b{ - position: absolute; - display: block; - height: 12px; - margin-bottom: 0px; - white-space: pre; - padding: floor(@basefontsize/4); - top: 0; - left: 0; - } - - span{ - color: @text-color; - z-index: 0; - min-width: 20px; - } - - b { + .lang-bar { z-index: 1; overflow: hidden; background-color: @rcblue; @@ -442,6 +435,9 @@ table.trending_language_tbl { // Changesets #changesets.rctable { + th { + padding: 0 1em 0.65em 0; + } // td must be fixed height for graph td { diff --git a/rhodecode/public/css/tags.less b/rhodecode/public/css/tags.less --- a/rhodecode/public/css/tags.less +++ b/rhodecode/public/css/tags.less @@ -13,15 +13,19 @@ font-size: (-1 + @basefontsize); //fit in tables line-height: .9em; border: none; + box-shadow: @button-shadow; .border-radius(@border-radius); font-family: @text-regular; background-image: none; color: @grey4; - .border ( @border-thickness-tags, @grey4 ); + .border ( @border-thickness-tags, @grey5 ); white-space: nowrap; a { color: inherit; - text-decoration: underline; + + &:hover { + color: @grey2; + } i, [class^="icon-"]:before, @@ -29,6 +33,10 @@ text-decoration: none; } } + + &:hover { + border-color: @grey4; + } } .tag0 { .border ( @border-thickness-tags, @grey4 ); color:@grey4; } diff --git a/rhodecode/public/css/type.less b/rhodecode/public/css/type.less --- a/rhodecode/public/css/type.less +++ b/rhodecode/public/css/type.less @@ -46,6 +46,13 @@ h6, .h6 { font-size: 1em; font-weight .breadcrumbs { font-size: @repo-title-fontsize; margin: 0; + width: ~"calc(100% - 180px)"; + float: left; + + h4 { + font-size: @basefontsize; + margin-bottom: 15px; + } } .breadcrumbs_light { @@ -156,6 +163,19 @@ pre { // Emphasis & misc // ------------------------- +.discreet { + color: @grey4; + font-size: 85%; + font-weight: normal; + + a { + color: @grey4; + + &:hover { + color: @rcdarkblue; + } + } +} small, .small { @@ -231,7 +251,8 @@ mark, clear: both; float: left; width: 100%; - margin: @pagepadding/2 0 @pagepadding; + margin: @pagepadding/2 0 @pagepadding/4; + min-height: 25px; .breadcrumbs { float: left; @@ -285,6 +306,11 @@ mark, } .title-content { + + &.repo-title { + float: none + } + float: left; margin: 0; padding: 0; diff --git a/rhodecode/public/css/variables.less b/rhodecode/public/css/variables.less --- a/rhodecode/public/css/variables.less +++ b/rhodecode/public/css/variables.less @@ -8,13 +8,15 @@ @rchighlightblue: lighten(@rcblue, 35%); // Secondary Colors (greyscale) -@grey1: #202020; //midnight -@grey2: #323232; //charcoal -@grey3: #666666; //tungsten -@grey4: #979797; //light grey +@black: #000; +@white: #fff; +@grey1: #2B2B2D; //midnight +@grey2: #5C5C5C; //charcoal +@grey3: #7E7F7F; //tungsten +@grey4: #949494; //light grey @grey5: #dbd9da; //greyish @grey6: #eeeeee; //silver -@grey7: #f9f9f9; //light silver +@grey7: #F5F5F5; //light silver // special for navigation @nav-grey: #CDCCCD; @@ -102,7 +104,7 @@ // FORMS (new) @border-thickness-inputs: 1px; -@input-padding: @button-padding; //needs to match button padding +@input-padding: .6em; //needs to match button padding // TODO: johbo: Needed for working computation of paddings around labels etc. // Expected to be replaced once we are done with the form refactoring. @input-padding-px: 12px; @@ -128,10 +130,14 @@ @fields-input-l: 720px; // BUTTONS -@button-padding: .9em; +@button-padding: .7em; +@button-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.07); + +// DROPDOWNS +@dropdown-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.07); // DEFAULT WIDTHS -@wrapper-maxwidth: 1200px; +@wrapper-maxwidth: 1600px; @sidebar-width: 145px; @sidebar-all-width: @sidebar-width + 2 * @sidebarpadding; @sidebar-small-width: 100px; diff --git a/rhodecode/public/fonts/RCIcons/config.json b/rhodecode/public/fonts/RCIcons/config.json new file mode 100755 --- /dev/null +++ b/rhodecode/public/fonts/RCIcons/config.json @@ -0,0 +1,623 @@ +{ + "name": "rcicons", + "css_prefix_text": "icon-", + "css_use_suffix": false, + "hinting": true, + "units_per_em": 1000, + "ascent": 850, + "copyright": "RhodeCode GmbH", + "glyphs": [ + { + "uid": "a5f9b6d4d795603e6e29a5b8007cc139", + "css": "bookmark", + "code": 59395, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M780 990L520 700C510 690 495 690 485 700L225 995C205 1015 180 1000 180 965V35C175 15 190 0 205 0H795C810 0 825 15 825 35V960C825 995 795 1010 780 990Z", + "width": 1000 + }, + "search": [ + "bookmark" + ] + }, + { + "uid": "fbc028d3a6a0df72f8f508ff5dfbab72", + "css": "tag", + "code": 59397, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M459.8 62.5L93.8 53.6C75.9 53.6 62.5 67 62.5 84.8L75.9 450.9C75.9 459.8 80.4 464.3 84.8 473.2L549.1 937.5C562.5 950.9 580.4 950.9 593.8 937.5L946.4 584.8C959.8 571.4 959.8 553.6 946.4 540.2L477.7 71.4C473.2 67 464.3 62.5 459.8 62.5ZM357.1 285.7C357.1 321.4 325.9 352.7 290.2 352.7 254.5 352.7 223.2 321.4 223.2 285.7 223.2 250 254.5 218.8 290.2 218.8S357.1 245.5 357.1 285.7Z", + "width": 1000 + }, + "search": [ + "tag" + ] + }, + { + "uid": "1c67c02366438b324c184ff9e356dca1", + "css": "branch", + "code": 59396, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M875 250C875 174.1 817 116.1 741.1 116.1S607.1 174.1 607.1 250C607.1 299.1 633.9 339.3 669.6 361.6 651.8 504.5 531.3 544.6 459.8 558V245.5C504.5 223.2 531.3 183 531.3 133.9 531.3 58 473.2 0 397.3 0S263.4 58 263.4 133.9C263.4 183 290.2 227.7 330.4 250V750C290.2 772.3 263.4 817 263.4 866.1 263.4 942 321.4 1000 397.3 1000S531.3 942 531.3 866.1C531.3 817 504.5 772.3 464.3 750V692C526.8 683 629.5 660.7 709.8 580.4 767.9 522.3 799.1 450.9 808 366.1 848.2 343.8 875 299.1 875 250ZM397.3 89.3C424.1 89.3 442 107.1 442 133.9S424.1 178.6 397.3 178.6 352.7 160.7 352.7 133.9 370.5 89.3 397.3 89.3ZM397.3 910.7C370.5 910.7 352.7 892.9 352.7 866.1S370.5 821.4 397.3 821.4 442 839.3 442 866.1 419.6 910.7 397.3 910.7ZM741.1 205.4C767.9 205.4 785.7 223.2 785.7 250S767.9 294.6 741.1 294.6 696.4 276.8 696.4 250 718.8 205.4 741.1 205.4Z", + "width": 1000 + }, + "search": [ + "branch" + ] + }, + { + "uid": "b75f7b47706aebd803ef370082e8e334", + "css": "group", + "code": 59407, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M961.5 630.8V646.2C961.5 650 957.7 657.7 950 657.7H788.5 784.6C769.2 638.5 746.2 619.2 707.7 615.4 673.1 607.7 653.8 600 638.5 592.3 646.2 584.6 657.7 580.8 669.2 576.9 715.4 569.2 726.9 553.8 734.6 542.3 742.3 530.8 742.3 519.2 734.6 503.8 726.9 488.5 703.8 461.5 703.8 423.1 703.8 384.6 703.8 319.2 776.9 319.2H784.6 792.3C865.4 323.1 869.2 384.6 865.4 423.1 865.4 461.5 842.3 492.3 834.6 503.8 826.9 519.2 826.9 530.8 834.6 542.3 842.3 553.8 857.7 569.2 900 576.9 953.8 580.8 961.5 623.1 961.5 630.8 961.5 630.8 961.5 630.8 961.5 630.8ZM253.8 646.2C269.2 630.8 292.3 615.4 323.1 611.5 361.5 603.8 384.6 596.2 396.2 584.6 388.5 576.9 376.9 569.2 361.5 565.4 315.4 557.7 303.8 542.3 296.2 530.8 288.5 519.2 288.5 507.7 296.2 492.3 303.8 476.9 326.9 450 326.9 411.5 326.9 373.1 326.9 307.7 253.8 307.7H246.2 234.6C161.5 311.5 157.7 373.1 161.5 411.5 161.5 450 184.6 480.8 192.3 492.3 200 507.7 200 519.2 192.3 530.8 184.6 542.3 169.2 557.7 126.9 565.4 80.8 573.1 73.1 615.4 73.1 619.2 73.1 619.2 73.1 619.2 73.1 619.2V634.6C73.1 638.5 76.9 646.2 84.6 646.2H246.2 253.8ZM707.7 634.6C634.6 623.1 611.5 600 600 580.8 588.5 561.5 588.5 542.3 600 519.2 611.5 496.2 650 450 653.8 388.5 657.7 326.9 653.8 223.1 534.6 219.2H519.2 503.8C384.6 223.1 380.8 323.1 384.6 384.6 388.5 446.2 423.1 492.3 438.5 515.4 450 538.5 450 557.7 438.5 576.9 426.9 596.2 403.8 619.2 330.8 630.8 257.7 642.3 246.2 711.5 246.2 719.2 246.2 719.2 246.2 719.2 246.2 719.2V742.3C246.2 750 253.8 757.7 261.5 757.7H519.2 776.9C784.6 757.7 792.3 750 792.3 742.3V719.2C792.3 719.2 792.3 719.2 792.3 719.2 788.5 715.4 780.8 646.2 707.7 634.6Z", + "width": 1000 + }, + "search": [ + "group" + ] + }, + { + "uid": "7ae0ef039bb0217d9581e44b09448905", + "css": "fork", + "code": 59409, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M792.3 196.2C792.3 138.5 746.2 96.2 692.3 96.2 634.6 96.2 592.3 142.3 592.3 196.2 592.3 230.8 611.5 261.5 638.5 280.8 626.9 365.4 569.2 403.8 511.5 423.1 453.8 407.7 396.2 369.2 384.6 280.8 411.5 261.5 430.8 230.8 430.8 196.2 430.8 138.5 384.6 96.2 330.8 96.2S223.1 138.5 223.1 196.2C223.1 234.6 246.2 269.2 276.9 284.6 288.5 392.3 353.8 473.1 457.7 511.5V673.1C426.9 692.3 407.7 723.1 407.7 761.5 407.7 819.2 453.8 861.5 507.7 861.5S607.7 815.4 607.7 761.5C607.7 723.1 588.5 692.3 557.7 673.1V511.5C661.5 473.1 726.9 392.3 738.5 284.6 769.2 265.4 792.3 234.6 792.3 196.2ZM326.9 161.5C346.2 161.5 361.5 176.9 361.5 196.2S346.2 226.9 326.9 226.9 292.3 215.4 292.3 196.2 307.7 161.5 326.9 161.5ZM507.7 796.2C488.5 796.2 473.1 780.8 473.1 761.5S488.5 726.9 507.7 726.9C526.9 726.9 542.3 742.3 542.3 761.5S526.9 796.2 507.7 796.2ZM692.3 161.5C711.5 161.5 726.9 176.9 726.9 196.2S711.5 226.9 692.3 226.9 657.7 211.5 657.7 192.3 673.1 161.5 692.3 161.5Z", + "width": 1000 + }, + "search": [ + "fork" + ] + }, + { + "uid": "65e66c3e7d74e2c345fb78fadd400d3f", + "css": "rhodecode", + "code": 59441, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M174.6 216.8C173.4 220.9 172.2 225 171 229.1 168.1 239.1 165.2 249.1 162.3 259.1 158.7 271.6 155 284.2 151.4 296.7 148 308.4 144.6 320.1 141.2 331.8 139 339.3 136.8 346.8 134.7 354.3 134.4 355.4 134.1 356.5 133.7 357.6 133.7 357.7 133.9 358.2 134 358.3 134.3 359 134.5 359.7 134.8 360.5 137.2 367.3 139.7 374.1 142.1 381 146 392 149.9 403 153.9 414.1 158.3 426.5 162.8 439 167.2 451.4 171.1 462.5 175.1 473.6 179 484.7 181.5 491.7 184 498.6 186.4 505.6 186.8 506.7 187.2 507.7 187.5 508.8 187.8 509.6 188.6 510.4 189 511.1 192.8 516.9 196.5 522.6 200.3 528.4 206.5 537.9 212.7 547.4 219 556.9 226.2 567.9 233.4 578.9 240.6 590 247.3 600.3 254.1 610.6 260.8 620.9 265.6 628.2 270.4 635.6 275.2 642.9 276.4 644.8 277.6 646.6 278.9 648.5 279.2 649 279.5 649.5 279.8 649.8 282.7 652.6 285.5 655.4 288.4 658.2 294.6 664.3 300.9 670.5 307.1 676.6 315.5 684.9 323.9 693.2 332.4 701.4 341.8 710.6 351.2 719.9 360.6 729.1 369.8 738.1 378.9 747.1 388.1 756.1 395.8 763.7 403.6 771.3 411.3 778.9 416.4 783.9 421.5 788.9 426.6 793.9 428.2 795.5 429.8 797.3 431.6 798.6 438.9 803.9 446.1 809.2 453.4 814.5 463.7 822 473.9 829.5 484.2 837 487.6 839.5 491.1 842 494.5 844.5 495.3 845.1 496.1 845.7 496.9 846.3 497.2 846.5 497.2 846.6 497.6 846.4 504.7 842.7 511.8 839.1 518.9 835.4 530.3 829.5 541.7 823.6 553.1 817.7 559.2 814.5 565.4 811.4 571.5 808.2 571.9 808 572.3 807.1 572.6 806.8 573.7 805.4 574.8 804 576 802.5 580.2 797.2 584.3 791.9 588.5 786.7 594.7 778.9 600.8 771.1 607 763.3 614.5 753.8 622 744.3 629.5 734.8 637.7 724.5 645.8 714.1 654 703.8 662.1 693.5 670.3 683.2 678.4 672.9 685.9 663.5 693.3 654 700.8 644.6 706.9 636.9 713 629.2 719.1 621.5 723.2 616.4 727.2 611.2 731.3 606.1 732.7 604.4 734 602.6 735.4 600.9 735.2 600.8 734.8 600.8 734.6 600.7 733.8 600.5 733 600.4 732.2 600.2 729.1 599.6 726 598.9 722.9 598.2 718 597.1 713 596 708.1 594.8 701.5 593.2 694.9 591.5 688.3 589.7 680.2 587.5 672.2 585.2 664.1 582.9 654.7 580.1 645.4 577.2 636.1 574.1 625.6 570.6 615.2 567 604.8 563.3 593.4 559.1 582 554.8 570.8 550.2 558.6 545.3 546.6 540.1 534.6 534.8 521.9 529.1 509.3 523.1 496.8 516.8 483.7 510.2 470.7 503.4 457.9 496.2 444.6 488.7 431.4 480.9 418.5 472.8 405.1 464.4 392 455.6 379.1 446.4 365.9 437 352.9 427.1 340.3 416.9 327.4 406.4 314.8 395.5 302.7 384.2 290.3 372.6 278.3 360.6 266.8 348.1 255.1 335.3 243.8 322.1 233.2 308.4 222.3 294.4 212 279.9 202.4 265 192.5 249.7 183.4 233.9 175 217.8 175 217.4 174.8 217.1 174.6 216.8ZM172.1 214.2C170.7 218.7 169.3 223.3 167.8 227.8 164.5 238.5 161.1 249.2 157.8 259.9 153.9 272.4 150 285 146.1 297.5 143 307.5 139.9 317.4 136.7 327.4 135.9 330.1 135 332.7 134.2 335.4 134 336.1 133.6 336.7 133.8 337.4 135.4 342.2 137 347.1 138.6 351.9 141.9 361.9 145.2 371.8 148.6 381.8 152.7 394.1 156.8 406.5 160.9 418.8 164.9 430.8 168.9 442.8 172.9 454.8 175.9 463.7 178.8 472.6 181.8 481.4 182.6 483.8 183.4 486.2 184.2 488.7 184.4 489.4 184.6 490.1 184.9 490.8 187.2 495 189.5 499.2 191.8 503.4 196.8 512.6 201.9 521.8 206.9 531 213.2 542.4 219.4 553.9 225.7 565.3 231.7 576.2 237.6 587.1 243.6 598 247.8 605.6 251.9 613.2 256.1 620.8 257.3 623 258.2 625.4 259.9 627.2 264.1 631.7 268.3 636.2 272.5 640.7 280.2 648.9 287.9 657.2 295.5 665.4 304.5 675 313.5 684.7 322.4 694.3 330.5 703 338.6 711.7 346.7 720.4 351.8 725.8 356.8 731.3 361.9 736.7 363.5 738.4 365 740 366.6 741.6 372.3 747.3 378 753 383.7 758.7 392.5 767.5 401.2 776.2 410 785 419.1 794.1 428.3 803.3 437.4 812.4 444.2 819.2 451.1 826.1 457.9 832.9 459.6 834.6 461.3 836.3 463 838 463.3 838.3 463.6 838.6 463.8 838.8 463.9 838.9 465.1 838.7 465.3 838.6 475.9 837.2 486.5 835.8 497 834.5 505.6 833.4 514.1 832.3 522.7 831.2 523 831.2 523.7 830.1 523.9 829.9 525.1 828.6 526.3 827.2 527.6 825.9 532.1 820.9 536.7 815.9 541.2 810.9 547.9 803.5 554.6 796.1 561.4 788.7 569.6 779.7 577.7 770.7 585.9 761.8 594.8 752 603.6 742.3 612.5 732.5 621.3 722.8 630.1 713.1 639 703.4 647 694.5 655.1 685.7 663.1 676.8 669.6 669.6 676.2 662.4 682.7 655.2 687 650.5 691.3 645.8 695.6 641 696.6 639.9 697.7 638.7 698.7 637.6 698.9 637.4 699.6 636.9 699.6 636.6 699.6 636.5 696.6 635.7 696.5 635.7 693.5 634.8 690.4 633.9 687.4 633 682.6 631.5 677.8 630 673 628.4 666.6 626.3 660.1 624.1 653.8 621.8 645.9 619 638.1 616.1 630.3 613.1 621.2 609.6 612.1 606 603.1 602.2 592.9 598 582.8 593.6 572.8 589 561.8 584 550.8 578.8 540 573.4 528.3 567.6 516.7 561.6 505.2 555.3 493 548.7 480.9 541.8 469 534.6 456.5 527.1 444.1 519.3 431.9 511.2 419.2 502.8 406.7 494 394.5 484.9 381.8 475.5 369.5 465.8 357.4 455.7 345 445.3 332.8 434.6 321.1 423.4 309.1 412 297.4 400.2 286.2 388 274.7 375.5 263.7 362.6 253.2 349.3 242.5 335.7 232.3 321.7 222.8 307.2 213 292.4 203.9 277.2 195.5 261.7 186.8 246.5 179 230.5 172.1 214.2ZM169.5 204C168.8 207.8 168.1 211.6 167.3 215.4 165.5 224.9 163.7 234.5 161.9 244 159.5 256.5 157.1 269 154.7 281.5 152.3 294.2 149.8 307 147.4 319.7 145.5 329.9 143.5 340.1 141.6 350.3 140.7 355.2 139.7 360.1 138.8 365 138.7 365.7 139.1 366.4 139.3 367 140.2 369.6 141.1 372.2 142 374.8 145.4 384.5 148.7 394.3 152.1 404 156.4 416.4 160.7 428.7 165 441.1 168.8 452.1 172.6 463 176.4 474 178.3 479.5 180.2 485 182.1 490.5 182.3 491.2 182.7 491.8 183 492.4 184.2 494.8 185.4 497.1 186.5 499.5 190.9 508.4 195.4 517.2 199.8 526.1 205.6 537.7 211.4 549.3 217.2 560.9 222.7 571.9 228.2 583 233.8 594 237.4 601.2 241 608.3 244.6 615.5 245.2 616.6 245.7 617.7 246.3 618.8 246.7 619.6 247.6 620.4 248.2 621.1 252.8 626.6 257.4 632.1 262 637.7 269.5 646.7 276.9 655.6 284.4 664.6 292.8 674.7 301.3 684.9 309.7 695 317.2 704 324.8 713.1 332.3 722.1 337 727.8 341.8 733.5 346.5 739.1 347.2 740 347.9 740.8 348.7 741.7 348.9 741.9 349.2 742 349.4 742.2 350.2 742.7 350.9 743.2 351.7 743.7 358.7 748.5 365.8 753.3 372.8 758.1 383.3 765.3 393.9 772.5 404.4 779.7 414.6 786.6 424.7 793.6 434.9 800.5 440.8 804.5 446.7 808.6 452.7 812.6 456.3 815.1 459.5 818.1 462.9 820.8 472.5 828.7 482.1 836.7 491.7 844.6 498.5 850.2 505.4 855.9 512.2 861.5 512.8 862 512.7 861.9 513.3 861.3 514.2 860.3 515.2 859.2 516.1 858.2 520 853.9 524 849.6 527.9 845.3 534 838.6 540.2 831.9 546.3 825.2 554 816.8 561.7 808.3 569.4 799.9 578.1 790.4 586.7 781 595.4 771.5 604.4 761.7 613.3 751.9 622.3 742.1 630.9 732.6 639.6 723.2 648.2 713.7 655.9 705.3 663.6 696.9 671.3 688.5 677.4 681.8 683.5 675.1 689.6 668.4 693.5 664.1 697.4 659.9 701.3 655.6 702.4 654.4 703.5 653.2 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652.1 701.6 651.3 701.5 651.3 698.5 650.5 695.5 649.5 692.6 648.6 687.9 647.1 683.1 645.5 678.4 643.8 672.1 641.6 665.8 639.2 659.5 636.9 651.8 634 644.1 630.9 636.4 627.8 627.5 624.1 618.6 620.3 609.7 616.4 599.7 612 589.8 607.4 580 602.7 569.2 597.5 558.4 592.1 547.7 586.6 536.2 580.6 524.8 574.4 513.4 568 501.4 561.2 489.5 554.2 477.7 546.9 465.3 539.3 453.1 531.4 441.1 523.3 428.6 514.8 416.3 506.1 404.2 497 391.7 487.7 379.5 478 367.5 468 355.2 457.8 343.2 447.2 331.5 436.3 319.6 425.2 308 413.6 296.8 401.7 285.4 389.6 274.5 377.1 264 364.3 253.3 351.2 243.2 337.8 233.6 323.9 223.8 309.8 214.6 295.4 206.1 280.5 197.4 265.4 189.4 249.9 182.1 234 177.7 224.2 173.5 214.2 169.5 204ZM866 183.5C863.9 179.4 861.1 176.2 857.1 174 851.9 171.1 846.2 168.9 840.7 166.5 829.5 161.7 818.2 157.4 806.7 153.4 783.6 145.4 760 138.9 736.3 132.9 711.7 126.7 687.1 120.9 662.3 115.7 637.1 110.4 611.7 105.6 586.3 101.4 561.2 97.2 536 93.1 510.5 91.1 497.8 90.1 485 89.9 472.4 91.3 465.9 92 459.4 93.2 453 94.2 446.6 95.2 440.1 96.2 433.7 97.3 408.2 101.5 382.8 106 357.4 111 332.2 115.9 307.1 121.2 282.1 126.9 257.2 132.5 232.6 139.2 208.4 147.3 196.3 151.4 184.2 155.8 172.3 160.5 166.4 162.8 160.5 165.2 154.6 167.7 151.7 168.9 148.8 170.2 145.8 171.4 143.2 172.5 140.6 173.5 138.1 174.7 134 176.7 130.6 179.7 128.3 183.6 127 185.8 126.2 188.2 125.3 190.6 124.2 193.6 123.1 196.6 122.1 199.6 118.1 211.5 114.9 223.7 112.5 236 107.7 260.4 106 285.4 106.8 310.2 107.2 322.7 108.2 335.3 109.7 347.7 111.2 360.2 112.7 372.8 115.1 385.2 119.8 410.4 126.7 435.1 134.8 459.3 138.9 471.4 143.3 483.5 147.9 495.4 152.2 506.5 157.5 517.3 162.7 528 173 549.2 184.4 569.8 196.6 589.9 208.8 609.9 221.9 629.3 235.7 648.1 249.5 666.8 264.1 685 279.3 702.6 295.3 721.1 311.7 739.2 328.6 756.9 345.6 774.8 363 792.2 381 809 398.9 825.9 417.4 842.2 436.4 857.8 445.6 865.4 454.9 872.8 464.2 880.2 473.6 887.7 483.1 895.1 492 903.2 494.3 905.2 496.5 907.3 498.7 909.5 498.9 909.7 499.7 910.8 500 910.8 500.2 910.8 500.5 910.8 500.7 910.8 501.2 910.8 502 911 502.5 910.8 507.3 907.1 512 903.3 516.8 899.6 526.2 892.1 535.6 884.6 544.9 876.9 563.3 861.7 581.4 846.2 599.2 830.3 616.9 814.5 634.1 798.2 651 781.5 667.9 764.7 684.4 747.5 700.3 729.7 716.3 711.8 731.8 693.4 746.5 674.4 761 655.7 774.8 636.5 787.8 616.8 800.7 597.2 812.8 577 823.8 556.2 835 535.1 845.2 513.5 854.3 491.4 863.4 469.1 871.2 446.3 877.3 423 883.4 399.9 887.8 376.4 890.3 352.7 892.9 328.6 893.4 304.3 892 280 891.8 276.9 891 273.8 890.3 270.7 889.7 267.7 889 264.6 888.4 261.6 887.2 255.7 886 249.9 884.7 244 882.3 233 879.7 222 876.5 211.1 873.4 201.8 870.1 192.5 866 183.5 863.5 178.4 878.8 211.7 866 183.5ZM814.8 393.5C808.1 418.2 799.5 442.5 789.4 466 780 487.9 770 509.6 758.5 530.5 747.4 550.7 735.1 570.3 722 589.3 708.8 608.4 694.7 626.8 680 644.8 664.8 663.4 649 681.5 632.7 699.1 615.9 717.3 598.5 734.9 580.5 752 562.5 769.1 544.1 785.7 525.1 801.6 515.7 809.5 506.1 817.3 496.5 824.9 496.1 825.2 495.2 826.3 494.7 826.3 494 826.3 493.3 826.3 492.6 826.3 492 826.3 491.4 825.5 491 825.1 490.5 824.6 490 824.1 489.5 823.6 488.4 822.6 487.2 821.5 486.1 820.5 481.6 816.6 476.9 813.1 472.2 809.4 469.9 807.6 467.6 805.7 465.3 803.8 463.1 801.9 461 799.8 458.8 797.8 454.2 793.7 449.7 789.6 445.2 785.5 435.9 777 426.6 768.5 417.5 759.8 408.4 751.1 399.5 742.3 390.9 733.2 386.7 728.8 382.7 724.3 378.4 720 374.2 715.8 370 711.5 365.8 707.2 349.1 690 332.9 672.5 317.4 654.3 301.8 636 286.9 617 273.1 597.3 259.2 577.5 246.4 556.9 234.5 535.8 222.8 515 212.1 493.7 202.6 471.8 193.1 449.9 184.8 427.4 177.9 404.6 176.1 398.6 174.4 392.6 173.1 386.5 171.7 380.1 170.6 373.6 169.6 367.1 167.6 354.2 166.3 341.2 165.5 328.2 164.7 315.3 164.3 302.3 164.5 289.3 164.7 276.7 165.9 264.2 167.5 251.7 167.9 248.5 168.3 245.4 168.7 242.2 168.9 240.6 169.1 239.1 169.3 237.5 169.5 235.9 169.6 234.3 169.8 232.7 170.1 230.3 171.1 228.1 171.7 225.7 172 224.5 172.2 223.2 172.2 221.9 172.2 220.8 172.8 220.1 173.6 219.5 174.6 218.8 175.6 218.3 176.5 217.5 177.1 217 177.6 216.6 178.4 216.3 179.2 216 180.1 215.7 180.9 215.3 183.9 214.2 186.8 213 189.8 211.9 195.7 209.7 201.6 207.5 207.6 205.3 231.3 196.7 255.3 189 279.7 182.4 292 179.1 304.3 176.1 316.7 173.5 322.9 172.2 329.1 170.6 335.4 169.3 341.7 167.9 348 166.6 354.3 165.4 379.8 160.4 405.4 156.3 431.1 152.5 444 150.6 457 148.8 470 147 473.2 146.6 476.5 146.1 479.7 145.7 481.3 145.5 482.8 145.3 484.4 145.1 485.7 144.9 487.1 145 488.4 145.1 493.9 145.1 499.5 145.3 504.9 146.3 506.2 146.5 507.4 146.8 508.6 147.1 510.1 147.5 511.5 147.8 513 148 516.1 148.4 519.2 148.9 522.3 149.3 528.6 150.2 534.8 151.1 541.1 152 553.7 153.8 566.4 155.7 579 157.7 604.4 161.7 629.7 166 654.8 171.4 680 176.8 705 183.2 729.7 190.3 742.1 193.9 754.4 197.7 766.6 201.7 772.7 203.7 778.7 205.8 784.7 207.9 787.7 209 790.7 210 793.7 211.1 795.1 211.6 796.6 212.1 798 212.7 798.7 213 799.4 213.2 800.1 213.5 800.8 213.8 801.9 214 802.4 214.5 803.6 215.7 805.3 216.5 806.3 217.9 806.8 218.7 807.1 219.5 807.2 220.5 807.3 221.2 807.2 221.8 807.4 222.5 807.7 223.4 807.9 224.3 808.1 225.2 809.8 231.5 811.2 237.9 812.3 244.4 813.4 250.8 814.1 257.2 814.5 263.6 814.7 266.8 814.8 270 814.9 273.2 814.9 274 814.9 274.7 814.9 275.5 814.9 276.3 815.2 277.1 815.3 277.8 815.7 279.5 816 281.1 816.4 282.8 821.3 306.5 822.7 330.7 820.7 354.8 819.6 367.7 817.6 380.7 814.8 393.5 807.1 421.7 822.5 357.6 814.8 393.5ZM617.6 393.5C616.1 389 614.6 384.5 613.1 379.9 612.9 379.3 612.7 378.7 612.5 378.1 612.4 377.7 612.5 377.1 612.4 376.7 612.3 376.1 612.2 375.5 612.1 374.9 611.8 373.8 611.4 372.8 610.8 371.9 609.7 370.1 608.1 368.5 606.5 367 604.7 365.2 602.4 362.7 599.6 362.7 601.6 360.7 604.3 360 606.5 358.3 607.6 357.4 608.5 356.5 609.7 355.7 610.5 355.2 611.6 354.7 612.1 353.8 612.3 353.4 612.4 352.9 612.4 352.5 612.9 352 613.3 351.5 613.7 350.9 614.4 349.8 614.7 348.6 614.9 347.3 615.1 345.1 615 342.9 615 340.7 615 338.4 615 336.1 615 333.8 615 331.4 615 329 614.4 326.6 613.1 321.5 610 316.8 606.4 313.1 604.7 311.4 603 309.9 601 308.6 598.3 306.9 595.5 305.5 592.7 304.1 589.9 302.7 586.9 301.8 583.8 301.4 581.4 301.1 579 301.1 576.6 301.1 573.9 301.1 571.2 301.1 568.5 301.1 556.2 301.1 543.8 301.1 531.5 301.1 526.9 301.1 522.3 301.1 517.7 301.1 516.9 301.1 516.1 301.1 515.2 301.1 515.1 301.1 515.2 305.3 515.2 305.6 515.2 308.8 515.2 311.9 515.2 315.1 515.2 316.2 515.2 317.3 515.2 318.4 515.2 318.9 515 319.1 515.5 319.1 516.7 319.1 528 319 528 319.2 528 327.2 528 335.2 528 343.2 528 355.8 528 368.3 528 380.9 528 384.6 528 388.3 528 392 528 392.2 528.1 393.4 527.9 393.4 525.4 393.4 522.8 393.4 520.3 393.4 518.9 393.4 517.6 393.4 516.2 393.4 515.9 393.4 515.2 393.2 515.2 393.6 515.2 395.7 515.2 397.8 515.2 400 515.2 401 515.2 414 515.2 414 524.7 414 534.3 414 543.8 414 549.3 414 554.8 414 560.2 414 561.4 414 562.5 414 563.7 414 564 414 563.8 411.1 563.8 410.7 563.8 405.1 563.8 399.6 563.8 394 563.8 393.4 563.9 393.5 563.3 393.5 562 393.5 560.7 393.5 559.3 393.5 557.8 393.5 556.3 393.5 554.8 393.5 554.6 393.5 553.5 393.7 553.5 393.4 553.5 388.4 553.5 383.4 553.5 378.4 553.5 375.6 553.5 372.9 553.5 370.1 553.5 369.4 553.5 368.8 553.5 368.1 553.5 367.7 554.2 367.9 554.5 367.9 557.4 367.9 560.2 367.9 563.1 367.9 565 367.9 566.9 367.9 568.8 367.9 570.1 367.9 571.6 367.7 572.8 368.1 573.9 368.4 574.8 369 575.7 369.7 576.8 370.6 578.3 371.8 578.9 373.1 579.2 373.8 579.2 374.5 579.2 375.3 579.2 376.6 579.6 377.7 580.2 378.9 580.7 380 581.3 381 581.6 382.2 581.7 382.6 581.7 383 581.8 383.4 581.9 384 582 384.6 582.1 385.1 583.1 390.9 584.2 396.6 585.2 402.4 585.6 404.9 586.1 407.3 586.5 409.8 586.6 410.3 586.7 410.8 586.8 411.3 586.8 411.4 587.2 411.4 587.4 411.4 597.8 411.4 608.3 411.4 618.7 411.4 619.2 411.4 619.6 411.4 620.1 411.4 620.2 411.4 620.2 410.7 620.2 410.6 620.2 408.2 620.2 405.7 620.2 403.3 620.2 398.3 620.2 393.3 620.2 388.4 620.2 388.4 620.2 388.4 620.2 388.4 619.3 390.1 618.5 391.8 617.6 393.5ZM592 339.7C592 342 589.2 342.8 587.7 344.1 587.4 344.3 587.1 344.6 586.9 344.8 586.7 344.8 586.4 344.8 586.2 344.9 585.8 345 585.4 345.2 585.1 345.4 584.4 345.9 583.9 346.6 583.2 347 582.1 347.5 580.7 347.3 579.6 347.3 577.9 347.3 576.3 347.3 574.6 347.3 573.9 347.3 573.2 347.3 572.5 347.3 569.5 347.3 566.4 347.3 563.4 347.3 563 347.3 558.8 347.4 558.8 347.2 558.8 337.9 558.8 328.5 558.8 319.2 558.8 319.1 571.7 319.2 573 319.2 577 319.2 581 319.1 584.9 320.1 586.4 320.5 587.8 321 589.2 321.6 590.1 322.1 591 323.2 591.6 324 593.1 325.7 594.1 327.8 594.5 330 594.6 330.7 594.6 331.3 594.6 332 594.3 332.6 594 333.2 593.7 333.9 593.3 334.7 592.9 335.5 592.6 336.3 592.1 337.4 592 338.5 592 339.7ZM722.6 393.5C722.6 384.2 722.6 374.9 722.6 365.6 722.6 357.1 720.9 348 714.6 341.9 707.5 335.1 696.4 333.9 687 334.7 685.1 334.9 683.2 335.3 681.4 336.1 680.4 336.5 679.5 336.9 678.6 337.6 678 338.1 677.3 338.5 676.7 338.8 673.6 340.4 670.5 341.6 668.8 344.9 668.8 335.9 668.8 326.8 668.8 317.8 668.8 311.9 668.8 306 668.8 300.1 668.8 298.4 668.8 296.6 668.8 294.9 668.8 294.4 669.1 293.7 668.5 293.7 657.9 293.7 647.3 293.7 636.7 293.7 635.5 293.7 634.2 293.7 633 293.7 633 293.7 633 297.8 633 298.1 633 303.4 633 308.7 633 314 633 314.3 633.8 314.2 634 314.2 635.4 314.2 636.7 314.2 638.1 314.2 640.6 314.2 643.2 314.2 645.7 314.2 645.9 314.2 645.8 319.4 645.8 319.8 645.8 331.2 645.8 342.6 645.8 353.9 645.8 364.9 645.8 375.8 645.8 386.8 645.8 388 645.8 389.2 645.8 390.3 645.8 391.2 645.7 391 644.6 391 641.6 391 638.7 391 635.7 391 634.8 391 633.9 391 633 391 632.9 391 632.9 391.9 632.9 392 632.9 397.7 632.9 403.4 632.9 409 632.9 409.8 632.9 410.5 632.9 411.3 632.9 411.5 633 411.5 633.2 411.5 634.5 411.5 635.9 411.5 637.2 411.5 649.1 411.5 661 411.5 672.9 411.5 673.4 411.5 681.5 411.5 681.5 411.5 681.5 406.5 681.5 401.5 681.5 396.5 681.5 394.7 681.5 392.9 681.5 391.1 681.5 391.1 675.6 391.1 675.2 391.1 674.8 391.1 668.7 391.1 668.7 391.1 668.7 389.8 668.7 388.5 668.7 387.3 668.7 381.2 668.7 375 668.7 368.9 668.7 366.5 668.7 364.2 668.7 361.8 668.7 361.3 668.7 360.9 668.7 360.4 668.7 360 670.3 358.8 670.6 358.5 671.7 357.5 672.8 356.5 674.2 355.8 674.7 355.5 675.3 355.3 675.8 355.3 676.5 355.2 676.8 354.8 677.4 354.3 678.5 353.5 679.7 353 681 352.8 683.6 352.4 685.8 352.7 687.9 354.2 689.1 355.1 690.1 356.1 691.2 357.2 692 358 692.7 358.8 693.3 359.8 694.2 361.6 694.3 363.7 694.3 365.7 694.4 369.3 694.3 372.9 694.3 376.6 694.3 387.8 694.3 399 694.3 410.3 694.3 410.9 694 411.6 694.7 411.6 696.4 411.6 698.1 411.6 699.8 411.6 706 411.6 712.3 411.6 718.5 411.6 722.4 411.6 726.3 411.6 730.2 411.6 730.2 411.6 730.2 398.5 730.2 397.5 730.2 395.4 730.2 393.3 730.2 391.2 727.8 391.8 725.2 392.6 722.6 393.5ZM730.3 270.6C727.9 270.6 725.4 270.6 723 270.6 722 270.6 721.1 270.6 720.1 270.6 720 270.6 719.6 271.3 719.6 271.4 716.5 276 713.4 280.6 710.4 285.3 708.9 287.5 707.4 289.7 706 292 705.6 292.5 705.3 293.1 704.9 293.6 704.6 294.1 704.8 294.9 704.8 295.4 704.8 295.6 704.8 298.8 704.8 298.8 705.4 298.8 706 298.8 706.5 298.8 709.5 298.8 712.4 298.8 715.4 298.8 717.8 298.8 720.1 298.8 722.5 298.8 723 298.8 722.7 299.6 722.7 299.9 722.7 301.4 722.7 302.9 722.7 304.4 722.7 305.8 722.7 307.1 722.7 308.5 722.7 309.3 723 309.1 723.8 309.1 725.3 309.1 726.9 309.1 728.4 309.1 728.7 309.1 730.3 309.3 730.3 308.9 730.3 306.2 730.3 303.4 730.3 300.7 730.3 300.4 730.1 298.8 730.5 298.8 731.9 298.8 733.3 298.8 734.6 298.8 734.7 298.8 735.4 298.8 735.4 298.8 735.4 298.2 735.4 297.7 735.4 297.1 735.4 296.9 735.4 293.7 735.4 293.7 734.1 293.7 732.9 293.7 731.6 293.7 731.1 293.7 730.3 294 730.3 293.4 730.3 285.7 730.3 278.1 730.3 270.6ZM722.6 285.9C722.6 287.2 722.6 288.5 722.6 289.7 722.6 290.6 722.6 291.4 722.6 292.3 722.6 292.5 722.7 293.4 722.6 293.6 722.5 293.7 721.6 293.6 721.5 293.6 720.6 293.6 719.7 293.6 718.8 293.6 717.5 293.6 716.2 293.6 715 293.6 716.3 291.6 717.7 289.6 719 287.6 719.6 286.7 720.2 285.9 720.8 285.1 722.4 283.1 722.6 280.7 722.6 278.2 722.6 280.8 722.6 283.4 722.6 285.9ZM763.6 288.5C760.9 285.8 756.2 285.9 752.6 285.9 752 285.9 751.4 285.9 750.8 285.9 750.8 285.9 750.8 284.8 750.8 284.7 750.8 283.4 750.8 282.1 750.8 280.8 750.8 280.7 763.9 280.8 765.2 280.8 765.7 280.8 766.2 281 766.2 280.5 766.2 279.1 766.2 277.7 766.2 276.4 766.2 275.3 766.2 274.2 766.2 273.2 766.2 273.2 764.9 273.2 764.9 273.2 759.2 273.2 753.5 273.2 747.8 273.2 747.2 273.2 746.5 273.2 745.9 273.2 745.7 273.2 745.7 273.6 745.7 273.8 745.4 276 745.1 278.2 744.9 280.4 744.3 284.8 743.8 289.3 743.2 293.7 747 293.7 751.5 293.1 755.1 294.8 757.9 296.2 759 299.4 758.5 302.4 758 305.8 754.4 306.5 751.5 306.5 749.6 306.5 743.2 307 743.2 303.9 742.3 306.5 741.5 309 740.6 311.6 742.3 311.6 744 312.6 745.6 313.2 748 314.1 750.5 314.3 753 314.1 756.9 313.8 761 312.5 763.6 309.4 766.3 306.1 766.2 301.9 766.2 297.8 766.2 295.6 766.2 293.3 765.7 291.1 765.5 290.1 765 288.6 763.7 288.5 763.7 288.5 763.6 288.5 763.6 288.5 761 285.9 766.2 288.5 763.6 288.5Z", + "width": 1000 + }, + "search": [ + "rhodecode" + ] + }, + { + "uid": "e5ad8728e6d6290aff4b6ffcfcaa9167", + "css": "up", + "code": 59442, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M686.5 595.8L513.6 379.1C506.3 369.9 492.4 369.9 485.1 379.1L312.2 595.8C302.7 607.8 311.2 625.4 326.5 625.4H672.2C687.5 625.4 696 607.8 686.5 595.8Z", + "width": 1000 + }, + "search": [ + "up" + ] + }, + { + "uid": "6e459e39444c93a2c017f258186765d6", + "css": "unlock", + "code": 59399, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M780.8 434.6H396.2V342.3C396.2 284.6 438.5 238.5 492.3 226.9 492.3 226.9 492.3 226.9 496.2 226.9 503.8 226.9 507.7 226.9 515.4 226.9 515.4 226.9 519.2 226.9 519.2 226.9 519.2 226.9 519.2 226.9 523.1 226.9 530.8 226.9 538.5 226.9 546.2 230.8 546.2 230.8 546.2 230.8 546.2 230.8 553.8 230.8 557.7 234.6 565.4 238.5 565.4 238.5 569.2 238.5 569.2 242.3 573.1 246.2 580.8 246.2 584.6 250 584.6 250 584.6 250 584.6 250 588.5 253.8 596.2 257.7 600 261.5 600 261.5 603.8 265.4 603.8 265.4 607.7 269.2 611.5 273.1 615.4 276.9 615.4 276.9 615.4 276.9 619.2 280.8 623.1 284.6 626.9 292.3 630.8 300 630.8 300 630.8 303.8 630.8 303.8 634.6 307.7 634.6 315.4 634.6 319.2 634.6 319.2 634.6 323.1 634.6 323.1 634.6 323.1 634.6 323.1 634.6 326.9 638.5 338.5 646.2 346.2 657.7 346.2H715.4C730.8 346.2 742.3 334.6 738.5 319.2 738.5 319.2 738.5 319.2 738.5 319.2 738.5 319.2 738.5 315.4 738.5 315.4 738.5 307.7 734.6 303.8 734.6 296.2 734.6 292.3 734.6 292.3 730.8 288.5 730.8 273.1 730.8 269.2 726.9 261.5 726.9 261.5 726.9 257.7 723.1 257.7 719.2 250 715.4 242.3 711.5 234.6 711.5 234.6 707.7 230.8 707.7 230.8 703.8 223.1 700 219.2 696.2 215.4 696.2 211.5 692.3 211.5 692.3 207.7 688.5 203.8 684.6 196.2 680.8 192.3 680.8 192.3 676.9 188.5 676.9 188.5 669.2 180.8 665.4 176.9 657.7 169.2 657.7 169.2 653.8 169.2 653.8 165.4 650 161.5 642.3 157.7 634.6 153.8 630.8 153.8 630.8 150 626.9 150 623.1 146.2 615.4 142.3 611.5 142.3 607.7 142.3 607.7 138.5 603.8 138.5 596.2 134.6 588.5 130.8 580.8 130.8 580.8 130.8 580.8 130.8 580.8 130.8 573.1 126.9 565.4 126.9 553.8 123.1 550 123.1 550 123.1 546.2 123.1 538.5 123.1 534.6 123.1 526.9 119.2 523.1 119.2 519.2 119.2 519.2 119.2 511.5 119.2 503.8 119.2 496.2 119.2 496.2 119.2 492.3 119.2 492.3 119.2 484.6 119.2 476.9 123.1 465.4 123.1 461.5 123.1 453.8 126.9 450 126.9 450 126.9 446.2 126.9 446.2 126.9 353.8 153.8 288.5 242.3 288.5 342.3V434.6H246.2C230.8 434.6 223.1 446.2 223.1 457.7V857.7C223.1 873.1 234.6 880.8 246.2 880.8H780.8C796.2 880.8 803.8 869.2 803.8 857.7V457.7C807.7 446.2 796.2 434.6 780.8 434.6Z", + "width": 1000 + }, + "search": [ + "unlock" + ] + }, + { + "uid": "b077586592b9b69166b981325446c836", + "css": "delete", + "code": 59392, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M515.4 92.3C303.8 92.3 130.8 265.4 130.8 476.9 130.8 688.5 303.8 861.5 515.4 861.5S900 688.5 900 476.9C900 265.4 726.9 92.3 515.4 92.3ZM742.3 507.7C742.3 523.1 730.8 534.6 711.5 534.6H315.4C300 534.6 284.6 523.1 284.6 507.7V446.2C284.6 430.8 296.2 419.2 315.4 419.2H711.5C726.9 419.2 742.3 430.8 742.3 446.2V507.7Z", + "width": 1000 + }, + "search": [ + "delete" + ] + }, + { + "uid": "dca63ad885c0d6f1780a8d1d55bc2380", + "css": "ok", + "code": 59393, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M515.4 115.4C303.8 115.4 130.8 288.5 130.8 500 130.8 711.5 303.8 884.6 515.4 884.6S900 711.5 900 500C900 288.5 726.9 115.4 515.4 115.4ZM753.8 411.5L450 715.4C438.5 726.9 423.1 726.9 411.5 715.4L273.1 576.9C261.5 565.4 261.5 550 273.1 538.5L315.4 496.2C326.9 484.6 342.3 484.6 353.8 496.2L411.5 553.8C423.1 565.4 438.5 565.4 450 553.8L669.2 334.6C680.8 323.1 696.2 323.1 707.7 334.6L750 376.9C765.4 384.6 765.4 400 753.8 411.5Z", + "width": 1000 + }, + "search": [ + "ok" + ] + }, + { + "uid": "c158b3a004c055c6ad1471cd98932268", + "css": "down", + "code": 59403, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M703.8 396.2L530.8 615.4C523.1 623.1 507.7 623.1 503.8 615.4L330.8 396.2C323.1 384.6 330.8 365.4 346.2 365.4H692.3C703.8 365.4 711.5 384.6 703.8 396.2Z", + "width": 1000 + }, + "search": [ + "arrow_down" + ] + }, + { + "uid": "02f59f392ad28056845cfc04cb121f13", + "css": "comment", + "code": 59394, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M130.8 784.6V280.8C130.8 207.7 188.5 150 261.5 150H769.2C842.3 150 900 207.7 900 280.8V569.2C900 642.3 842.3 700 769.2 700H273.1C269.2 700 261.5 703.8 257.7 707.7L165.4 800C153.8 815.4 130.8 803.8 130.8 784.6ZM261.5 211.5C223.1 211.5 188.5 242.3 188.5 284.6V696.2L234.6 650C238.5 646.2 242.3 642.3 250 642.3H769.2C807.7 642.3 842.3 611.5 842.3 569.2V280.8C842.3 242.3 811.5 207.7 769.2 207.7H261.5Z", + "width": 1000 + }, + "search": [ + "comment" + ] + }, + { + "uid": "9a44b838872ca62b8aba7bbbbf67cc59", + "css": "feed", + "code": 59400, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M842.3 111.5H188.5C153.8 111.5 130.8 138.5 130.8 169.2V826.9C130.8 857.7 157.7 884.6 188.5 884.6H846.2C876.9 884.6 903.8 857.7 903.8 826.9V169.2C900 138.5 873.1 111.5 842.3 111.5ZM307.7 776.9C269.2 776.9 234.6 746.2 234.6 703.8S265.4 630.8 307.7 630.8C346.2 630.8 380.8 661.5 380.8 703.8S346.2 776.9 307.7 776.9ZM553.8 788.5C519.2 788.5 496.2 761.5 496.2 730.8 496.2 619.2 407.7 530.8 296.2 530.8 265.4 530.8 230.8 503.8 230.8 473.1 230.8 438.5 253.8 411.5 284.6 411.5L296.2 411.5C473.1 411.5 615.4 553.8 615.4 730.8 611.5 761.5 584.6 788.5 553.8 788.5ZM750 788.5C715.4 788.5 692.3 761.5 692.3 730.8 692.3 511.5 511.5 330.8 292.3 330.8 261.5 330.8 226.9 303.8 226.9 269.2 226.9 234.6 250 207.7 280.8 207.7L292.3 207.7C576.9 207.7 811.5 438.5 811.5 726.9 811.5 761.5 784.6 788.5 750 788.5Z", + "width": 1000 + }, + "search": [ + "feed" + ] + }, + { + "uid": "e0118d6f20b76d77317977ae8dc849d7", + "css": "left", + "code": 59401, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M692.3 76.9L761.5 146.2C773.1 157.7 773.1 173.1 761.5 184.6L473.1 473.1C461.5 484.6 461.5 500 473.1 511.5L769.2 807.7C780.8 819.2 780.8 834.6 769.2 846.2L700 915.4C688.5 926.9 673.1 926.9 661.5 915.4L257.7 511.5C246.2 500 246.2 484.6 257.7 473.1L653.8 76.9C665.4 65.4 680.8 65.4 692.3 76.9Z", + "width": 1000 + }, + "search": [ + "left" + ] + }, + { + "uid": "3cea97f90c8f2b0a90833855434f58de", + "css": "right", + "code": 59402, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M338.5 915.4L265.4 846.2C253.8 834.6 253.8 819.2 265.4 807.7L553.8 519.2C565.4 507.7 565.4 492.3 553.8 480.8L257.7 184.6C246.2 173.1 246.2 157.7 257.7 146.2L326.9 76.9C338.5 65.4 353.8 65.4 365.4 76.9L769.2 480.8C780.8 492.3 780.8 507.7 769.2 519.2L376.9 915.4C365.4 926.9 346.2 926.9 338.5 915.4Z", + "width": 1000 + }, + "search": [ + "right" + ] + }, + { + "uid": "820a44cb2e7fc1d0e28b1d2a8cd44cb9", + "css": "git", + "code": 59434, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M928.8 6.3H71.3C35 6.3 6.3 36.3 6.3 71.3V927.5C6.3 963.8 36.3 992.5 71.3 992.5H927.5C963.8 992.5 992.5 962.5 992.5 927.5V71.3C993.8 36.3 963.7 6.3 928.8 6.3ZM200 555C203.8 566.3 208.8 575 213.8 582.5 220 590 227.5 596.3 236.3 600 245 603.8 255 606.3 265 606.3 273.8 606.3 281.3 605 288.8 603.8 296.3 602.5 302.5 600 308.8 597.5L315 546.3H287.5C283.8 546.3 280 545 277.5 542.5 276.3 541.3 275 537.5 275 535L280 496.2H385L368.7 627.5C361.2 633.8 352.5 638.7 343.7 642.5 335 646.3 326.3 650 316.2 652.5 306.2 655 297.5 657.5 286.3 658.8 276.3 660 265 661.3 252.5 661.3 232.5 661.3 215 657.5 198.7 650 182.5 642.5 168.7 632.5 157.5 620 146.2 607.5 137.5 592.5 131.2 575 125 557.5 121.2 538.8 121.2 518.8 121.2 501.3 123.7 485 127.5 468.8 131.2 452.5 137.5 438.8 145 425 152.5 411.3 161.2 400 171.2 388.8 181.2 377.5 192.5 368.8 205 361.3 217.5 353.8 231.3 347.5 246.3 343.8 261.3 340 276.3 337.5 292.5 337.5 306.3 337.5 317.5 338.8 328.7 341.3 340 343.8 350 347.5 357.5 351.3 366.2 355 373.8 360 380 365 386.3 370 392.5 376.3 397.5 381.3L377.5 412.5C373.8 417.5 368.8 420 363.8 421.3 358.8 422.5 353.7 421.3 347.5 417.5 342.5 413.8 337.5 411.3 333.7 408.8 328.7 406.3 325 403.8 320 402.5 315 401.3 310 400 305 398.8 300 397.5 293.7 397.5 287.5 397.5 273.7 397.5 261.2 400 250 406.3 238.7 412.5 228.7 420 221.2 431.3 212.5 441.2 206.2 455 202.5 468.8 197.5 483.8 196.2 500 196.2 517.5 195 531.3 197.5 543.8 200 555ZM536.3 657.5H465L503.7 342.5H575L536.3 657.5ZM878.8 398.8H798.8L766.3 657.5H696.3L727.5 398.7H647.5L655 342.5H886.3L878.8 398.8Z", + "width": 1000 + }, + "search": [ + "git" + ] + }, + { + "uid": "ea152b092f5ad7d610de2c388553e188", + "css": "hg", + "code": 59437, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M926.6 9.2H73.9C37.9 9.2 8.7 38.5 8.7 74.4V927.1C8.7 963.1 38 992.3 73.9 992.3H926.6C962.6 992.3 991.8 963 991.8 927.1V74.4C991.8 38.4 962.6 9.2 926.6 9.2ZM444 657.4H373.5L389.8 524.1H276.7L260.4 657.4H189.9L228.6 344.2H299.1L282.8 476.4H395.9L412.2 344.2H482.7L444 657.4ZM621 555.8C624.3 566.8 629.1 576 635.3 583.5 641.5 591 648.8 596.8 657.5 600.8 666.1 604.8 675.6 606.8 686.1 606.8 694.7 606.8 702.4 606 709.3 604.5 716.2 603 722.8 600.8 729.1 598.1L735.1 546.9H708.4C704.1 546.9 700.8 545.8 698.6 543.6 696.4 541.4 695.5 538.5 695.9 534.9L700.6 496.2H805.1L788.8 627.1C780.8 633 772.5 638.1 763.9 642.3 755.3 646.6 746.3 650 736.9 652.7 727.5 655.5 717.6 657.5 707.2 658.7 696.8 660 685.7 660.6 674 660.6 654.6 660.6 637 657 621 650 605 642.9 591.3 633.1 579.9 620.7 568.5 608.2 559.7 593.5 553.5 576.4 547.2 559.3 544.1 540.9 544.1 520.9 544.1 503.6 546.1 487.1 550 471.3 554 455.6 559.6 441.1 566.9 427.8 574.2 414.5 583 402.4 593.2 391.7 603.4 381 614.9 371.8 627.4 364.2 639.9 356.6 653.5 350.7 667.9 346.6 682.4 342.6 697.6 340.5 713.5 340.5 726.8 340.5 738.9 341.7 749.7 344.2 760.5 346.6 770.2 349.9 778.8 353.9 787.4 358 795.1 362.8 801.8 368.1 808.6 373.5 814.5 379 819.7 384.8L797 413.2C793.3 418.2 788.8 421.3 783.7 422.3 778.6 423.4 773.2 422.2 767.8 418.8 762.8 415.4 758.1 412.4 753.6 409.9 749.2 407.4 744.7 405.3 740.1 403.7 735.5 402 730.7 400.8 725.6 400 720.5 399.2 714.8 398.8 708.5 398.8 694.9 398.8 682.4 401.7 671.1 407.5 659.8 413.3 650 421.5 641.9 432 633.7 442.5 627.4 455.2 622.9 469.9 618.4 484.7 616.1 501 616.1 518.7 615.9 532.5 617.6 544.8 621 555.8Z", + "width": 1000 + }, + "search": [ + "hg" + ] + }, + { + "uid": "4a842c0afb4c35dacd21da71f9fed3f1", + "css": "comment-add", + "code": 59439, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M952.4 591.9V274.9C952.4 268.4 952.3 261.9 951.8 255.4 950.7 242.9 948.2 230.6 944.1 218.8 936.5 196.6 923.8 176.2 907.3 159.6 890.8 143.1 870.6 130.4 848.5 122.7 836.6 118.6 824.2 115.9 811.6 114.8 805.3 114.2 798.9 114.2 792.6 114.2H216.9C204 114.2 191.3 114.1 178.5 116 166.3 117.9 154.4 121.2 143 125.9 121.4 134.8 101.9 148.7 86.4 166.2 70.8 183.8 59.3 205 53.1 227.7 49.7 240.1 47.9 252.8 47.6 265.6 47.3 278.7 47.6 291.8 47.6 304.9V861.8C47.6 870.7 52.5 878.6 60.5 882.5 67.3 885.9 75.6 886.2 82.4 882.7 84.8 881.5 86.9 879.7 88.8 877.8 91.1 875.5 93.4 873.2 95.6 871 100.3 866.3 105 861.6 109.7 856.9L137.9 828.6C147.3 819.2 156.6 809.9 166 800.5 175.2 791.3 184.6 782.1 193.7 772.7 197.7 768.5 201.9 764.4 207.6 762.7 210.4 761.9 213.2 761.8 216 761.8H782.7C795.5 761.8 808.3 762 821 760.1 844.8 756.5 867.7 747.3 887.3 733.3 906.2 719.9 922.1 702.1 933.2 681.8 945.1 660.2 951.5 636 952.2 611.4 952.5 604.9 952.4 598.4 952.4 591.9ZM883.4 285.1V602.5C883.4 608.8 883.4 615.1 882.5 621.4 881.7 627.5 880.2 633.6 878.1 639.4 874.4 649.4 868.8 658.7 861.7 666.7 846.6 683.6 825.1 693.8 802.5 695.1 796.3 695.4 790 695.2 783.8 695.2H207.8C201.2 695.2 194.7 695.2 188.1 695.2 185 695.2 181.8 695.2 178.8 696.1 176.2 696.9 173.9 698.2 171.8 699.9 169.6 701.7 167.6 703.7 165.6 705.7 163.3 708 161 710.3 158.7 712.6 154 717.3 149.4 721.9 144.7 726.6 135.3 736 126 745.3 116.6 754.7V270C116.6 257.8 118.8 245.7 123.7 234.6 128 224.9 134 215.9 141.5 208.4 157.5 192.4 179.6 183.3 202.2 183.3H791.5C797.6 183.3 803.7 183.3 809.7 184.2 832 187.4 852.4 199.4 866 217.4 872.8 226.4 877.7 236.7 880.5 247.6 882 253.5 882.9 259.6 883.1 265.8 883.6 272.2 883.4 278.7 883.4 285.1ZM668.8 402H538.2C534.4 402 526.7 394.3 526.7 390.5V263.7C526.7 256 519 248.3 515.2 248.3H465.3C457.6 248.3 449.9 256 449.9 259.8V390.4C449.9 394.2 442.2 401.9 438.4 401.9H311.7C304 401.9 296.3 409.6 296.3 413.4V463.3C296.3 471 304 478.7 307.8 478.7H434.5C442.2 478.7 449.9 486.4 449.9 490.2V617C449.9 624.7 457.6 632.4 461.4 632.4H511.3C519 632.4 526.7 624.7 526.7 620.9V494.1C526.7 486.4 534.4 478.7 538.2 478.7H665C672.7 478.7 680.4 471 680.4 467.2V417.3C680.3 409.6 672.6 402 668.8 402Z", + "width": 1000 + }, + "search": [ + "comment-add" + ] + }, + { + "uid": "2427f6b8d4379b9a0b41cf31780807cf", + "css": "comment-toggle", + "code": 59440, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M797.6 114.2H202.4C116.6 114.2 47.6 183.3 47.6 269V861.9C47.6 881.4 69.5 891.1 84.1 881.8 86.4 880.7 88.6 879.1 90.6 877.1L199.8 768C202.1 765.7 204.7 764 207.7 762.8 209.7 762.2 211.9 761.9 214.3 761.9H797.6C883.4 761.9 952.4 692.8 952.4 607.1V269C952.4 183.2 883.3 114.2 797.6 114.2ZM118.3 752.6V269.5C118.3 222.5 156.4 184.3 203.5 184.3H680.1C593.7 267.9 175.5 695.4 171.4 699.5L118.3 752.6Z", + "width": 1000 + }, + "search": [ + "comment-toggle" + ] + }, + { + "uid": "6533bdc16ab201eb3f3b27ce989cab33", + "css": "folder-open-empty", + "code": 61717, + "src": "fontawesome" + }, + { + "uid": "d64b34fac1d9923b7d29d1550b628ecd", + "css": "lock", + "code": 59398, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M812.5 424.1H758.9V317C758.9 308 758.9 303.6 758.9 299.1 758.9 294.6 758.9 290.2 758.9 285.7 758.9 281.3 758.9 281.3 758.9 276.8 758.9 267.9 758.9 263.4 754.5 254.5 754.5 250 754.5 250 750 245.5 750 236.6 745.5 232.1 741.1 223.2 741.1 223.2 741.1 218.8 736.6 218.8 732.1 209.8 727.7 200.9 723.2 192 723.2 192 718.8 187.5 718.8 187.5 723.2 178.6 718.8 169.6 714.3 165.2 714.3 160.7 709.8 160.7 709.8 156.3 705.4 151.8 700.9 142.9 696.4 138.4 696.4 138.4 692 133.9 692 133.9 683 125 678.6 120.5 669.6 111.6 669.6 111.6 665.2 111.6 665.2 107.1 660.7 102.7 651.8 98.2 642.9 93.8 638.4 93.8 638.4 89.3 633.9 89.3 629.5 84.8 620.5 80.4 616.1 80.4 611.6 80.4 611.6 75.9 607.1 75.9 598.2 71.4 589.3 67 580.4 67 580.4 67 580.4 67 580.4 67 571.4 62.5 562.5 62.5 549.1 58 544.6 58 544.6 58 540.2 58 535.7 58 535.7 58 531.3 58 531.3 58 526.8 58 526.8 58 526.8 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 517.9 58 513.4 58 513.4 58 513.4 58 508.9 58 508.9 58 504.5 58 504.5 58 500 58 500 58 500 58 500 58 495.5 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 486.6 58 486.6 58 486.6 58 482.1 58 482.1 58 477.7 58 477.7 58 473.2 58 468.8 58 468.8 58 464.3 58 455.4 58 442 62.5 433 67 433 67 433 67 433 67 410.7 67 397.3 71.4 388.4 75.9 383.9 75.9 383.9 80.4 379.5 80.4 375 84.8 370.5 84.8 361.6 89.3 361.6 93.8 357.1 93.8 357.1 93.8 348.2 98.2 339.3 102.7 334.8 111.6 334.8 111.6 330.4 111.6 330.4 116.1 321.4 120.5 317 125 308 133.9 308 133.9 303.6 138.4 303.6 138.4 299.1 142.9 294.6 151.8 290.2 156.3 290.2 160.7 285.7 160.7 285.7 165.2 276.8 169.6 272.3 178.6 272.3 183 267.9 183 267.9 187.5 267.9 187.5 263.4 196.4 258.9 205.4 254.5 214.3 254.5 214.3 254.5 218.8 250 218.8 250 232.1 245.5 236.6 245.5 245.5 245.5 250 245.5 250 241.1 254.5 241.1 263.4 236.6 267.9 236.6 276.8 236.6 281.3 236.6 281.3 236.6 285.7 236.6 290.2 236.6 294.6 236.6 299.1 236.6 303.6 236.6 312.5 236.6 317V424.1H187.5C169.6 424.1 160.7 437.5 160.7 450.9V915.2C160.7 933 174.1 942 187.5 942H808C825.9 942 834.8 928.6 834.8 915.2V450.9C839.3 433 825.9 424.1 812.5 424.1ZM361.6 317C361.6 250 410.7 196.4 473.2 183 473.2 183 473.2 183 477.7 183 486.6 183 491.1 183 500 183 500 183 504.5 183 504.5 183 504.5 183 504.5 183 504.5 183 513.4 183 517.9 183 526.8 183 526.8 183 526.8 183 531.3 183 593.8 196.4 642.9 250 642.9 317V424.1H361.6V317Z", + "width": 1000 + }, + "search": [ + "lock" + ] + }, + { + "uid": "d95fde5e3bfeb3302efc47c90538a1c5", + "css": "more", + "code": 59410, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M546.2 415.4H446.2C430.8 415.4 419.2 426.9 419.2 442.3V542.3C419.2 557.7 430.8 569.2 446.2 569.2H546.2C561.5 569.2 573.1 557.7 573.1 542.3V442.3C573.1 426.9 561.5 415.4 546.2 415.4ZM546.2 107.7H446.2C430.8 107.7 419.2 119.2 419.2 134.6V234.6C419.2 250 430.8 261.5 446.2 261.5H546.2C561.5 261.5 573.1 250 573.1 234.6V134.6C573.1 119.2 561.5 107.7 546.2 107.7ZM546.2 723.1H446.2C430.8 723.1 419.2 734.6 419.2 750V850C419.2 865.4 430.8 876.9 446.2 876.9H546.2C561.5 876.9 573.1 865.4 573.1 850V750C573.1 734.6 561.5 723.1 546.2 723.1Z", + "width": 1000 + }, + "search": [ + "more" + ] + }, + { + "uid": "34e7772638ae3ca1bfb0a4eca2c39221", + "css": "merge", + "code": 59443, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M199.8 740.5C199.8 812.2 258.1 870.5 329.8 870.5S459.8 812.2 459.8 740.5C459.8 694.6 435.8 654.5 399.8 631.3 418.4 491.7 533.4 451.9 602.4 440.6V742.4C563.7 765 537.4 806.4 537.4 854.4 537.4 926.1 595.7 984.4 667.4 984.4S797.4 926.1 797.4 854.4C797.4 806.5 771.1 765 732.4 742.4V254.9C771.1 232.3 797.4 190.9 797.4 142.9 797.4 71.2 739.1 12.9 667.4 12.9S537.4 71.2 537.4 142.9C537.4 190.8 563.7 232.3 602.4 254.9V309.9C542.2 317.8 440.4 342.3 364.2 417.8 309.5 472.1 277.9 542.1 269.6 625.9 228.4 647.7 199.8 690.6 199.8 740.5ZM667.6 897.8C643.7 897.8 624.3 878.3 624.3 854.5S643.8 811.2 667.6 811.2C691.5 811.2 710.9 830.7 710.9 854.5S691.5 897.8 667.6 897.8ZM667.6 99.6C691.5 99.6 710.9 119 710.9 142.9S691.4 186.2 667.6 186.2C643.7 186.2 624.3 166.8 624.3 142.9S643.7 99.6 667.6 99.6ZM329.9 783.9C306 783.9 286.6 764.4 286.6 740.6S306.1 697.3 329.9 697.3C353.8 697.3 373.2 716.7 373.2 740.6S353.8 783.9 329.9 783.9Z", + "width": 1000 + }, + "search": [ + "merge" + ] + }, + { + "uid": "c95735c17a10af81448c7fed98a04546", + "css": "folder-open", + "code": 59405, + "src": "fontawesome" + }, + { + "uid": "865ac833a8efcfc24a6f573705ce56b1", + "css": "svn", + "code": 59438, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M933.4 9.2H80.7C44.7 9.2 15.5 38.5 15.5 74.4V927.1C15.5 963.1 44.8 992.3 80.7 992.3H933.4C969.4 992.3 998.6 963 998.6 927.1V74.4C998.7 38.4 969.4 9.2 933.4 9.2ZM167.9 447.1C171.1 451 175.4 454.4 180.8 457.3 186.2 460.2 192.2 463 199 465.4 205.7 467.8 212.7 470.5 219.8 473.3 226.9 476.2 233.9 479.5 240.7 483.2 247.5 486.9 253.6 491.6 259 497.2 264.4 502.8 268.7 509.6 271.9 517.4 275.1 525.3 276.8 534.8 276.8 545.8 276.8 561.6 274.1 576.4 268.6 590.3 263.1 604.3 255.3 616.4 245.1 626.8 234.9 637.2 222.5 645.4 208 651.5 193.4 657.6 177 660.7 158.8 660.7 149.7 660.7 140.7 659.7 131.5 657.7S113.6 652.8 105.2 649.2C96.8 645.5 89 641.2 81.8 636.2 74.6 631.2 68.5 625.6 63.5 619.5L88.5 586.7C90.5 584.3 93 582.3 95.9 580.7 98.8 579.1 101.8 578.3 104.8 578.3 108.8 578.3 112.7 579.7 116.5 582.5 120.3 585.3 124.5 588.4 129.1 591.8 133.7 595.2 139 598.2 145.1 601.1 151.2 603.9 158.7 605.3 167.6 605.3 180.7 605.3 190.7 601.7 197.8 594.7 204.9 587.6 208.4 577.1 208.4 563.2 208.4 556.8 206.8 551.4 203.5 547.3 200.3 543.1 196 539.7 190.8 536.8 185.6 533.9 179.6 531.4 172.8 529.1 166 526.9 159.2 524.5 152.1 521.9 145.1 519.3 138.2 516.2 131.4 512.8 124.6 509.3 118.6 504.7 113.4 499 108.2 493.3 103.9 486.4 100.7 478.2 97.5 469.9 95.9 459.8 95.9 447.7 95.9 433.8 98.5 420.4 103.7 407.6 108.9 394.8 116.4 383.4 126.2 373.5 136 363.6 147.8 355.7 161.7 349.8 175.6 343.9 191.3 341 208.6 341 217.5 341 226.1 341.9 234.5 343.8S250.8 348.2 258.1 351.6C265.4 354.9 272.1 358.8 278.1 363.3 284.1 367.8 289.2 372.8 293.4 378.1L272.3 407C269.7 410.3 267.2 412.8 264.8 414.4 262.4 416 259.4 416.8 256 416.8 252.7 416.8 249.4 415.8 246.1 413.6 242.8 411.4 239.1 409.1 235 406.5 230.9 403.9 226.2 401.6 220.9 399.4 215.6 397.2 209.3 396.2 202.2 396.2 195.6 396.2 189.8 397.1 184.9 399 179.9 400.9 175.8 403.4 172.5 406.8 169.2 410.1 166.7 414 165.1 418.4 163.5 422.9 162.6 427.8 162.6 433 163.1 438.4 164.7 443.2 167.9 447.1ZM480 657.4H416.3L339.2 343.7H395.6C401.6 343.7 406.4 345.1 410 348 413.6 350.8 415.8 354.5 416.7 359L449.4 531.8C451.3 538.7 453 546.3 454.6 554.8 456.2 563.2 457.5 571.9 458.7 581 461.7 572 464.9 563.2 468.4 554.8 471.8 546.4 475.4 538.8 479.2 531.8L552.3 359C553.2 357.1 554.4 355.2 556.1 353.4 557.7 351.5 559.6 349.8 561.8 348.4 564 347 566.4 345.8 569 345 571.6 344.2 574.4 343.7 577.3 343.7H634.1L480 657.4ZM902.6 657.4H866C860.5 657.4 856.1 656.5 852.8 654.7 849.4 652.9 846.2 649.9 843.2 645.8L733.6 452.2C733.3 456.2 733 460.1 732.7 463.8 732.3 467.6 732 471.1 731.7 474.4L710.2 657.4H648.2L686.9 343.7H723.9C726.9 343.7 729.5 343.8 731.6 344 733.7 344.2 735.5 344.7 737.1 345.5 738.7 346.3 740.1 347.4 741.4 348.8S744.1 352.1 745.5 354.4L855.5 548.1C855.8 543.1 856.2 538.3 856.7 533.7 857.2 529.2 857.8 524.8 858.3 520.8L879.4 343.6H941.4L902.6 657.4Z", + "width": 1000 + }, + "search": [ + "svn" + ] + }, + { + "uid": "bbfb51903f40597f0b70fd75bc7b5cac", + "css": "trash", + "code": 61944, + "src": "fontawesome" + }, + { + "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", + "css": "trash-empty", + "code": 59406, + "src": "fontawesome" + }, + { + "uid": "f8aa663c489bcbd6e68ec8147dca841e", + "css": "folder", + "code": 59404, + "src": "fontawesome" + }, + { + "uid": "c8585e1e5b0467f28b70bce765d5840c", + "css": "docs", + "code": 61637, + "src": "fontawesome" + }, + { + "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", + "css": "doc", + "code": 59414, + "src": "fontawesome" + }, + { + "uid": "5408be43f7c42bccee419c6be53fdef5", + "css": "doc-text", + "code": 61686, + "src": "fontawesome" + }, + { + "uid": "b091a8bd0fdade174951f17d936f51e4", + "css": "folder-empty", + "code": 61716, + "src": "fontawesome" + }, + { + "uid": "c08a1cde48d96cba21d8c05fa7d7feb1", + "css": "doc-text-inv", + "code": 61788, + "src": "fontawesome" + }, + { + "uid": "178053298e3e5b03551d754d4b9acd8b", + "css": "doc-inv", + "code": 61787, + "src": "fontawesome" + }, + { + "uid": "e99461abfef3923546da8d745372c995", + "css": "cog", + "code": 59415, + "src": "fontawesome" + }, + { + "uid": "98687378abd1faf8f6af97c254eb6cd6", + "css": "cog-alt", + "code": 59416, + "src": "fontawesome" + }, + { + "uid": "21b42d3c3e6be44c3cc3d73042faa216", + "css": "sliders", + "code": 61918, + "src": "fontawesome" + }, + { + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu", + "code": 61641, + "src": "fontawesome" + }, + { + "uid": "c5fd349cbd3d23e4ade333789c29c729", + "css": "eye", + "code": 59417, + "src": "fontawesome" + }, + { + "uid": "7fd683b2c518ceb9e5fa6757f2276faa", + "css": "eye-off", + "code": 59418, + "src": "fontawesome" + }, + { + "uid": "2e2dba0307a502a8507c1729084c7ab5", + "css": "cancel-circled2", + "code": 59419, + "src": "fontawesome" + }, + { + "uid": "0f4cae16f34ae243a6144c18a003f2d8", + "css": "cancel-circled", + "code": 59420, + "src": "fontawesome" + }, + { + "uid": "26613a2e6bc41593c54bead46f8c8ee3", + "css": "file-code", + "code": 61897, + "src": "fontawesome" + }, + { + "uid": "5211af474d3a9848f67f945e2ccaf143", + "css": "remove", + "code": 59408, + "src": "fontawesome" + }, + { + "uid": "44e04715aecbca7f266a17d5a7863c68", + "css": "plus", + "code": 59421, + "src": "fontawesome" + }, + { + "uid": "4ba33d2607902cf690dd45df09774cb0", + "css": "plus-circled", + "code": 59422, + "src": "fontawesome" + }, + { + "uid": "1a5cfa186647e8c929c2b17b9fc4dac1", + "css": "plus-squared", + "code": 61694, + "src": "fontawesome" + }, + { + "uid": "2d3be3e856fc1e4ac067590d2ded1b07", + "css": "plus-squared-alt", + "code": 61846, + "src": "fontawesome" + }, + { + "uid": "eeadb020bb75d089b25d8424aabe19e0", + "css": "minus-circled", + "code": 59423, + "src": "fontawesome" + }, + { + "uid": "f755a58fb985eeb70bd47d9b31892a34", + "css": "minus-squared", + "code": 61766, + "src": "fontawesome" + }, + { + "uid": "18ef25350258541e8e54148ed79845c0", + "css": "minus-squared-alt", + "code": 61767, + "src": "fontawesome" + }, + { + "uid": "861ab06e455e2de3232ebef67d60d708", + "css": "minus", + "code": 59424, + "src": "fontawesome" + }, + { + "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", + "css": "info-circled", + "code": 59425, + "src": "fontawesome" + }, + { + "uid": "9dd9e835aebe1060ba7190ad2b2ed951", + "css": "search", + "code": 59411, + "src": "fontawesome" + }, + { + "uid": "b429436ec5a518c78479d44ef18dbd60", + "css": "paste", + "code": 61674, + "src": "fontawesome" + }, + { + "uid": "8772331a9fec983cdb5d72902a6f9e0e", + "css": "scissors", + "code": 59412, + "src": "fontawesome" + }, + { + "uid": "9a76bc135eac17d2c8b8ad4a5774fc87", + "css": "download", + "code": 59413, + "src": "fontawesome" + }, + { + "uid": "eeec3208c90b7b48e804919d0d2d4a41", + "css": "upload", + "code": 59426, + "src": "fontawesome" + }, + { + "uid": "5d2d07f112b8de19f2c0dbfec3e42c05", + "css": "spin", + "code": 59448, + "src": "fontelico" + }, + { + "uid": "9bd60140934a1eb9236fd7a8ab1ff6ba", + "css": "spin-alt", + "code": 59444, + "src": "fontelico" + }, + { + "uid": "513ac180ff85bd275f2b736720cbbf5e", + "css": "home", + "code": 59427, + "src": "entypo" + }, + { + "uid": "d4816c0845aa43767213d45574b3b145", + "css": "history", + "code": 61914, + "src": "fontawesome" + }, + { + "uid": "c43db6645e7515889fc2193294f50767", + "css": "plus", + "code": 59411, + "src": "custom_icons", + "selected": false, + "svg": { + "path": "M873.1 446.2H619.2C603.8 446.2 592.3 434.6 592.3 419.2V165.4C592.3 150 580.8 138.5 565.4 138.5H465.4C450 138.5 438.5 150 438.5 165.4V419.2C438.5 434.6 426.9 446.2 411.5 446.2H157.7C142.3 446.2 130.8 457.7 130.8 473.1V573.1C130.8 588.5 142.3 600 157.7 600H411.5C426.9 600 438.5 611.5 438.5 626.9V880.8C438.5 896.2 450 907.7 465.4 907.7H565.4C580.8 907.7 592.3 896.2 592.3 880.8V626.9C592.3 611.5 603.8 600 619.2 600H873.1C888.5 600 900 588.5 900 573.1V473.1C900 457.7 888.5 446.2 873.1 446.2Z", + "width": 1000 + }, + "search": [ + "plus" + ] + }, + { + "uid": "7d7f338d90203f20c0d8d5c26091cc69", + "css": "minus", + "code": 59412, + "src": "custom_icons", + "selected": false, + "svg": { + "path": "M980 560H20C10 560 0 550 0 540V380C0 370 10 360 20 360H985C995 360 1005 370 1005 380V545C1000 550 990 560 980 560Z", + "width": 1000 + }, + "search": [ + "minus" + ] + }, + { + "uid": "4ccc61480001600f2e7e3c7dd0546c6e", + "css": "remove", + "code": 59413, + "src": "custom_icons", + "selected": false, + "svg": { + "path": "M975 140L860 25C845 10 825 10 810 25L525 310C510 325 490 325 475 310L190 25C175 10 155 10 140 25L25 140C10 155 10 175 25 190L310 475C325 490 325 510 310 525L25 810C10 825 10 845 25 860L140 975C155 990 175 990 190 975L475 690C490 675 510 675 525 690L810 975C825 990 845 990 860 975L975 860C990 845 990 825 975 810L690 525C675 510 675 490 690 475L975 190C990 180 990 155 975 140Z", + "width": 1000 + }, + "search": [ + "remove" + ] + }, + { + "uid": "b1afcccc053ecb95fbcacf06e5c0d554", + "css": "history", + "code": 59418, + "src": "custom_icons", + "selected": false, + "svg": { + "path": "", + "width": 1143 + }, + "search": [ + "history" + ] + } + ] +} \ No newline at end of file diff --git a/rhodecode/public/fonts/RCIcons/rcicons.eot b/rhodecode/public/fonts/RCIcons/rcicons.eot index ce6f326628a5965923e7d2be0c2efb33a5de778b..041a625cef455f924ff6020314e110f7355ddc65 GIT binary patch literal 18076 zc%0pQdw3kxedu}2duC^6c4uZETCG<5)XRG8YIpsRWgFX)5wbJLc#G;ks0>kXF#_X}-r+N6Y#hU7N1%}pUsn$TvU_a-9EJq(6#XX%e;y!v_}Id&|F(DO4QLMlou8RI zF!7(Rd-5@;-vRNvk4@Zq9A8VIJdQ#iXCJ@o|LKL;vJ&kI$W0_{O>)>_%uK z(2YFBaHr!-M-bxrmd-7mi z2~o+PDvvJf$XAf&PaQ%Ed=Xk|%2$A_!-#Ae*}4nqGZPE5D2}+M{N^y8nLacD?fWsv z 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 Fe*wN;eU|_L diff --git a/rhodecode/public/fonts/RCIcons/rcicons.svg b/rhodecode/public/fonts/RCIcons/rcicons.svg --- a/rhodecode/public/fonts/RCIcons/rcicons.svg +++ b/rhodecode/public/fonts/RCIcons/rcicons.svg @@ -1,78 +1,134 @@ -Copyright (C) 2017 by original authors @ fontello.com +Copyright (C) 2019 by original authors @ fontello.com - + - + + + - + + + - + + + - + - + + + - + + + - + + + - + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + - + + + - + + + - + + + - + - + + + - + + + - + + + - + - + + + - + + + - + + + - + + + - + + + - + + + - + - + + + + + + + \ No newline at end of file diff --git a/rhodecode/public/fonts/RCIcons/rcicons.ttf b/rhodecode/public/fonts/RCIcons/rcicons.ttf index ce04da872ddf44d907a0b38a0d8c7316ecada14e..567538e5a7fbcac3d5306bd158d27bf86f0a0721 GIT binary patch literal 17912 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 A3IG5A diff --git a/rhodecode/public/fonts/RCIcons/rcicons.woff b/rhodecode/public/fonts/RCIcons/rcicons.woff index beb0f4362bf5241b14955e441c04e312149215a9..ce1edfade12afa523e7c7211219ef9697849ab77 GIT binary patch literal 10764 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 diff --git a/rhodecode/public/fonts/RCIcons/rcicons.woff2 b/rhodecode/public/fonts/RCIcons/rcicons.woff2 index f33e01713cf9a983e07481a6021b9cbd7144f33b..57e99161f3477a5f5ec4bc8f8ef04091d5e743ec GIT binary patch literal 9124 zc$@*GBU{{ePew8T0RR9103)OT3jhEB07du!03%WW0RR9100000000000000000000 z0000SR0dW6ibe|WWY%~KfdBvjHUcCAfqVoY1%*Keg(Vw9II|+yH~=Vk-v<%Zo5QpJ zI)R%Jg875$=4pk3Q$lP7)QCD%v08;)9BnZ_C=>`q*CP{(z9G`BW_HscbxEhD(k*F}8c0Y& zPa)6`gf2D?HB<{05*3ld28yM0Z1t|=DQ86#u7CyW-&r0r=%$odRX?tIsC+ZO{T_=U zo>U3o@7=w>yd^v}T!S{QO;H>{jA4OQ@bUBJEMJ-|yeB1FlBGb)nP3UPFi^@C0CJJ8 z(*HME3bdT?cD4kw%#MBiK!B`m_wFRobw&#$D}^2qpj-Zbs_J@2<&^Ii3{)z!xiQbo zBoABJQkEfEw!;A+?{ENf0OdS_bSo5a zZsU5oZ*8f+oR8?IbE@3f0(PP^WpH7sa1R-MavbT2E+NJC7{#B)h1??4l=AkHeXHzn z#+7};51#w?&DXc=`cF51`0$e-olYPaGxyKTs=GYGTfb0qr)RD^sX>!@`RO)4@BSZo zynOrufC$FHWq^zQrLCi@r*B|rWNcz;W^Q3=Wo=_? zXYT+agA74)A^$2mV6tZx0tk?V07VEe2mvlafSVBDAq02{0X{;2pAZlr1Oy2IAwocy z5D*~*XhMKV2(SnNQ9?kB5D+H>BnSaXLO_ZTkR}9V2mx6_K#mZQCj=A-0YySUi4agG z1XKtCRYE{bV+T;z*atK;4ggJ!LqJR82+-Cz26Qw|09}n!Ku_Zg(AT&E3^e-&V5r$Y z07jbq95B}Ge*qKC{tB3C4ht~T95!ICIXb{XbM%0v=HvlZnv)M$YtCB0Mst1uY&GX0 zV5d1x0DH~(2sr3M9?$sg!Y_bDL84(O+E+-a&le2C74m@OMhF4|%q~$`P$Jc>B$i;y z04C6FAd<}_$3WNxPZngG*cw#o;;EFG82Nm3%HOmO-FkBOtOes^QbX^c_wtx7>r)@< zqP}!~X}9Y-SuI$$n5Rwr)#~~C=Grn%zj<*-FURF;T?4KI-y=PHNw+nt@4;$U?Yqb0 z>AW$@cwc`+fBEao&3J3oF!$w$leS{9sA@Zt_^UHJyrEi2_CCv4Y_j znvPDBp2Q6u87b8@YH#gtnoBp5Y3|L^DoE18kAD%1T%)ucKqxHEs6L3X=NGl4z7gy; ztDGl7#e%-+marY9#I9pC@ke%mIllccN=r@LYYpZ(xeDfV1fQn1!Iaoawg2p8Bgu<; z(1GjCR6XV~SjStvrr3E@9^THY<7(s{c2ocC@-5s^og1~m5q0b}rW#BhN}fuB>8_1x z%tvw}rk@>{tN4cUq?;S%2rP2Pc_~!v6)Wh=#<+Y{ZWY_qmL`IVB74L`gYwiGDhxD6 zGMPi1EDbUyKmu;*i)#I0$jOojD2dca6T%7U5flKqPJ)X-1Nq?Ds1TQu2cI@TQiC}j z;?tCcDQh;00EoX?h_iFKX_*)NkL_lD=#Nd&R1TFG=A=fdN7YFHxvO6~L-A!%Sr*y|E{ z-Z3t&O|RkY5NDL_zK(rEktPiQZe7D8l$P#jMZN`?-SWnVpgvGy=2R5 z$ZSaGY3JpEf_2#xVBsCIs1c-gaO8P2ZdSk&gyCLflG?`EJmD^v`X? z|2sbSt6%Ed^t#?(vvb;6=aCmm+S!-n&1rn&Q6wv)*$qdqTKFfaO;!^h{xhnMTb3Vz zqReh2qjf#xJ@AVEJa9+aAsfL)SCe2i{XVu~}~U+ShHqsB|^ zVpaDK3SEpz#qeGcko%kAPhibuyaBD>TREc+I4-~)>YLBjA_QYgulqp6GKyv@c>!=u z+*WpcM>kkMqLTW(VwCNz6@O4d9vjz;V0IVlWFRK z5MP?I=!sc<&wg`1O28yc;jUg0)Wj{l~9r8ne;FpKaY;C%ucGA(%I&Q}P4#1;0hT^Wsoz4E8yetfn(LNn2s}kIfv%#~`fByA9 zzat9C|NsAAul+)>HNGhB#lEszH{c+;?_RDE?&@W6oI)on_grNQ{TF#dNWw)Pxyx;j zXE)s(MJPy;AolM%GP|Pv&XDwZFe-G9W_lIpgQ;@WsCPt-3T)1K(n#X^Ige}Zc&@S7 z3JxbUKz_AjMX>?az21!LQoDxazsFm1NfNX90#i@gM%R& zvE6hWH}hq1X6}Y8+MK4w??7P?O69`fzc82v@Y02m_hK4l-C)uiwZ{EvU>d`YpoR0e zedKy@tbmQ*LM6lm)6z=4GJ|n5q}0H~R(P zP}Qd)gU@T@-T-*EHTu&918SgNw^lh}4OmT~Fb$MS5z~R?Kr~wOD-HPB(60W^WsI3_WJBEo7l#YBrql7_`{Sqg)_%rd`^=US&{{lm5xTyR!)w& zVsd%x-16|M)lGzB$eCp~#Q+LC1ogW82QXPrbzvl>b*W70mA>}I8(ZmMQZu#5))gjT z1N=7?H*ebR7uf)#ir0$7 zq8=fr>xmLLHQF^gxpY!n$*=r;?%XclfgL6afoaAGUs(wS9}@ z{Wia6{sE^`h5-mc=;XxVe0g>&+xpryltLj8q{blTI!r;x7!-qpJ*o)sDX9cN6Es5& zAy$q9L?$O7Mlj}5PKbm65q`>c6xlYTwf6QXCPk?Mkw6oO00vrsPZ}YD%vu#~haiT& z1?oT|Bw!7e01o&9quxG}ka7SJv+x?D>-z}MfM6Tybx1?vgzAI|D0OJUcl_ypZQaHh z)eQuoyClJ}Kp?tOYAPu00_-+Kk4Nrkd*j;udGXbY-Q?;rFbNWNr*qpcs^OlxwJeGK zIF??NL$oiNfm(wkfRP*d@qKHOp!*e_G%37oA9X7RZ&E`vEgs-kZU0= z38=db{6(O70{$hF$h>xQ0(xkdHPtxB!g(;AgOvD%=Nwu?8~(wri(ig&yZ|n><+%(j z`R}cDp_1KPnDFV0Dnw_9r8S|%nGsbRnbi4DLID(prlocO4_QXpMeH}`a^S38V*M;A z@n!yr(v-_Qd^H4sr@yg*4M#wFNbfMLK{x5fYI%)zU5*Wc(^NBM>>_D;4K8|M%|&q< zXL!y|h;3+p*42QQx9$)N?AsZbwmuh3leaj)VGim7FwQ%WYcnK-3`x#~KPV3?`-zJw zaZ(*WTc{J)tmP@Pa2ll`$oQY6YV%>8=lOU(qx0s0NYfXyaO86wd$EhS=`MpaBk>x! zk?6%pD)5+w!W!T*;v9~=v6oooR4L1jzlR*vlogFi*5|83_WOTFF--J+ajr>#fP9<2)z};Ao!DVO(0D>>5G3ee1 zVHjcoNW*1HeAe@4X-qJ|^y-|KyrRLu%SC5<2?dD}Mum?=9W_Bd7WrRgwlY&L&s660 zMcUDcF0ZC9XHQ`#4Vx)nX>AlAa*T1CfqatYWnAhvX;K}hZkeNwUDwshZtb#hY!4sW z+4ioTZlFc|Q4(}a@Qbkf35FeBtj5QsihN+T7B0u{Dl z=jt*T0@V61szgLP2@3Qh8Nht(s>dJq-~!Sf^p9_s*GEKwh`udG83JM=B0#_Gwqb2T zRDqZqQ3OIm4Mb2Pk4=JdTr|E@Mja&gQOC*C&hfzmzf6_ICXEUJaQ}4s_{pmIVDjzF z3kw26)U7^@5&#G#W`w~yjsYMljaS&j3hi{9f=nuAgj1e)0DwayiBLfyNfDst`zk_h zhytoYM2hte1_Kc-Dj`a(#@V;Zw1WU3W5$ulwPJKi2N51eaF2Dde%Z2uAo6+FRpdu5 zT=E5%RsOGla@%m5`&-_3ToJcJeRaR{lLdEq?~Sz!yn17L@4NCLH&mIIrwrw_aNUQw zOm}eh1TK#+rnHL~>&PLMc zz@NBWTZ z+PS5l-PKC9oq363?-Wru60f z{gVms;J*qVY$T-@%ue;(*4*P6v^T*0#lg^?=51>VlzJ-j@BY&lL(_Ur_MYsiz1l$2 zc+0&Mp31!qbS1PGdkKK>SSi^_E~R`;YK$_MUz6o8@zokW<0;F5MgsJj!kY$K7FKk0 z{02ML{MfPXH+;u(uQIRR2<63#CE7+~M|4G1Y&+Z<*;YNhEqpuL7FS&sxdx;(YD?6M zss-Evn$?5-7K`mTCUhV8tp86hE@74|xOYd6Hu57>=`Rx}8dJVZBxu8D^q8AMR6kqe zr}3YyGd}4$W$XUIEZs{(4=H~COtVBmC=)a zYkfX_>h|uo9|HQ))!g>abW2}5%}V{;&I1bhJg0@%!W}3Y;|}7RxZ}nT9P8^u>F>X* z%MKmNq?8z=M!18x(Sx}lq9D>_scR;}IabT;508hfiP%_FLGRfSSYxFn{F$D9nOK?< zxndnDxjL57MCv8d%lA~LMP@Lp39$uAT0&#ZrWXxmw4z2r6LEvOf?oGvW=bYSH(Zsb z5@+M4a^ob7PUt1j%Fj$qi_p?b_3@D~LA89B^=0&;4d8u2q{T8xq?tXIg@HW75Jx$qBx?7V`$zcS@WhwQ7Z}S2$T$Ib(~B=wWKG} z@k)JU)Z$$~fbvqSE5Y(Mz?N4PtYiGNQ`M6-RE_ba#;KZdO+T75 z$fm5a$!RWT;x|1PX$YqAgZQNDTPRzm9v483pAez_+B3sUbSY*?GdKR4D2)CHah;6- zoGzb?#QS3EWEWS=G?Nt8@5q;e4(00OxY;_SNHY>q!%U|-BZ3VUk+EpLny;zo===?K zv{z~PhVBxRY6e?z&sq%zvU7{Bq$Hv1fa4@j)@UY^o%he&mb!r0PQQj9t-p4z_Cs%N^EI$wkk(!5SL*ia7Iu5v zd|$T++vl}U)`4S$-1ilGUyFMy5VVyEPgirC#*tCZxN(T!Mn|{<(x<1Zs8FU^XuDIYo?eTia`fhp?!ox(!B|^Jh`S3v?PCT(geiyA zMGW!2d!%Cu=gd_dS6TJX#4gGZNmJdH`P6jQuOOS2x0sLVczuF> zW?87>4&vn=jbj(H#OEnmQkYQybw1Eo`40$xpJ??^;>KHb^u;xd#X8@xms(U4KO1_-omhPX zgQ{I*_8?dZx=MP>4<{D0`(;#5JZF-R`$fI;LP3&hDVt`&O+CHTQJpn3I`UnIn!=JD zy8MGD6GT`NGZ51rm;HMylPx@@;oskV2G zxt7jSaLCI@Ejq(#Yvp>3{ola&LU-y(-h`|a$!ynnEMERcF&keI%EuFPxT5R}F(7gw63wEQ zY+L7W4FN?IwfoWdzh8DYEzr1;z=n1+j#8|^#2V`_XDf>sgi!t!tDPp2pd@WrG?V8) z#c|*js31%cS>@t6SucP6i}j1`C6-1pvhp^@@kuDDzhMztht4B7P&s}*+Jf3=!0*=A z!F>F>BXwk12|O2_QMA zz{`7#**hQ*l6oz-y5W7pd*!8a?nMysXK1y*2ygQuBYF6<^NwGea!gg+iItd}b?u$zKPf zh%J+sB>4J&BdKM(iK!vQH*LwjGm=o;Pl<1t%i?ZjoO$u39Fs$!%1cgp$L_ZORDXVX z9BWQ0Se z_V}1_jkApd81NjHO=bAgxN@8h-|H#i_(Y>Bw@1v6I|^kTOcP=8WLLpqh!`c~FPk?4 zz-)=TD(6kfP+GbT$Jm$)fXts2EM6$P30RH>`zja&k~ElE73#^Acd&x43%+bCyZId8 z%J4dTCjNAyw$+M{X5fLV9FLcu+S<7ARZ`azr5-SLse=h&wLC^R4rM@|$Lx@0cCPi; zdK`lc{V1QeX6YPAl;-v@`Md2dWajm-{AI@gSQ%P2BWr})gB1_9q9*PjeiwJ#$nCu? zlkRP79P8KN;n!Bq$fC{ZOrdV>u3fuJo8U#7cIEKl(LY8x14W}{-t8Q#^ys2{Bb>pa zk#e9~RjQ{e-e7bURf452WCe5sO|?-98VD<7EP$$a7(i3*=s?+FJZ&14ZBv(*u86)*DD)QILE_{ExxM?IZpiPQ?}vZuU2tjwUtA}E|P;!#tyGL zJDaL$T%CQTuL3@YGc&V~AE$t3A3s(Kb?kVSv;ZA`fTb;l7hg~i54f6w!nkdFpjtK8 z!5J)aa0l^{d-OPGoXg`lIlI%f)NT5YAR$JW%=9kggkIkM;{g}enC9|dKk|mAl7qP% zr!h{I`SFie9%@UMj^>Elcl_9Fl1dB9=BP9U3;)U>oBNU`twxQv-w3B?Nv1Rsnr~MTP<4Eh zrRk}u-K@zhI%tYCsA!txlnkI+JSSWeQ86JsIiL#GPN+&wuAVTn#BX*=3O$(n`Rw$u z@Qy*f{!CZ2IjcugTN~F?lKA;#8H@XxZ)};Jf@`t*>w3GMW~H_F*{OTdKmGb4eUq1= z*`WF^O21*^EeAFFO1k2W1Qj)8?R)Pfs^pruC z9YRwEzD1v+iMg(SCOy`RJe~Bw8RXf(HS>^9(!r@r@kBH{V=tB9^yfa0pDQyd@%V7A zkA#JhsQ;vfA^?0_=gebu`^@u`N$ax;yd*?6CODXtKAd}J zYc?x{LjX&X#)^pOjv;wwk#V?Yv37W6>wbfJP{UF9_}{%$uBXng+$jKP7Km*>y!9D_ z@ff7!my9-Y^=Fe?S!-lL$#a*3kz>%C%&e$4YGsThi`_T5{5Q|Ac+Np)4%2#;$?cT_ ziqCMI5aP6#D?~+Hn&98Qb+ZV~fs`lafLODo?a%rDhu^pV7^F}nmPloCg;J%~Xmw1MsF=8fq?ELbtem`p zqLQ+Ts+zinrk1vjuAaVup^>qPshPQjrIodft)0DtqmzYsxTSU$5e%+a1=bu)1J;4@ z6a?-nc%6=Hh`QO3JCo?ZwIP63!jh_U8d;mtX{uprtJYVn9`!hH&rQHj)k Pathfinder in Illustrator +to build a compound image. It may happen that your image is rasterized, in which +case it will need to be converted to vector; check the results carefully. + + .. note:: + When adding to the existing icon collection, please maintain our + existing icon style. + + +Creating The Font +----------------- + +*Fontello* + +We use fontello.com to generate the font files. On the main page, there is a +section for clicking and dragging icons to add to a font. If you would like to +use the existing font icons, here you will need to drag the .json file from the +current fontello folder. Once it has preloaded all of the existing fonts, drag +any new .svg icons into this same section to add them. + +Any icons which appear blank or incorrect will need to be rebuilt in Illustrator. +This likely means that the paths have not been generated correctly; check the +settings in the Pathfinder tool. + +After all of the icons are loaded into fontello, resist the temptation to click +the big red button; there's another task to do. Each icon has a pencil button; +click *every* icon - including the pre-existing ones - and check the settings. +Each current icon should have the same hex code as that which is listed in +rcicons.less. The "default css name" should be its simplified name; this is what +will be prepended with "icon-" for the CSS classes. Also remove any unnecessary +information from the keywords. + +Once you have checked the icons, click the button in fontello which downloads a +zip file of the new font. + + +Preparing The LESS Files +------------------------ + + .. note:: + It's a good idea to have `grunt watch` running in the background for this. + +First, obviously the font files located in the unzipped folder under "font" +should replace the existing files in rhodecode/public/fonts/RCIcons/. While +doing this, check the permissions of the files that they have not changed; they +should be set to `chmod 644` but fontello's files may be different. + +Next, you'll need to open the rcicons.css file which comes in the fontello .zip +and match the @font-face declaration to the one at the top of +rhodecode/public/css/rcicons.less, making sure to adjust the paths to +/fonts/RCIcons/. + +In the same file, you will see the CSS for each icon. Take a quick look to make +sure that the existing icons haven't changed; if they have, you'll need to +adjust the content. Add any new icons to rcicons.less (note that similar ones +have been grouped together). + +If you haven't yet, you'll need to run grunt to compile the LESS files; see the +developer documentation for instructions. + diff --git a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js --- a/rhodecode/public/js/rhodecode/base/keyboard-bindings.js +++ b/rhodecode/public/js/rhodecode/base/keyboard-bindings.js @@ -98,7 +98,7 @@ function setRCMouseBindings(repoName, re }); Mousetrap.bind(['g c'], function(e) { window.location = pyroutes.url( - 'repo_changelog', {'repo_name': repoName}); + 'repo_commits', {'repo_name': repoName}); }); Mousetrap.bind(['g F'], function(e) { window.location = pyroutes.url( diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -131,6 +131,7 @@ function registerRCRoutes() { pyroutes.register('repo_new', '/_admin/repos/new', []); pyroutes.register('repo_create', '/_admin/repos/create', []); pyroutes.register('repo_groups', '/_admin/repo_groups', []); + pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []); pyroutes.register('repo_group_new', '/_admin/repo_group/new', []); pyroutes.register('repo_group_create', '/_admin/repo_group/create', []); pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []); @@ -148,6 +149,7 @@ function registerRCRoutes() { pyroutes.register('repo_group_list_data', '/_repo_groups', []); pyroutes.register('goto_switcher_data', '/_goto_data', []); pyroutes.register('markup_preview', '/_markup_preview', []); + pyroutes.register('file_preview', '/_file_preview', []); pyroutes.register('store_user_session_value', '/_store_session_attr', []); pyroutes.register('journal', '/_admin/journal', []); pyroutes.register('journal_rss', '/_admin/journal/rss', []); @@ -195,14 +197,17 @@ function registerRCRoutes() { pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); + pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); + pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']); + pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); + pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']); + pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']); pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); - pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']); - pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']); pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']); pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']); @@ -356,6 +361,12 @@ function registerRCRoutes() { pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []); pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []); pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []); + pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']); + pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']); + pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']); + pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']); + pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']); + pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']); pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']); pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']); pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']); diff --git a/rhodecode/public/js/src/rhodecode.js b/rhodecode/public/js/src/rhodecode.js --- a/rhodecode/public/js/src/rhodecode.js +++ b/rhodecode/public/js/src/rhodecode.js @@ -102,7 +102,7 @@ var showRepoStats = function(target, dat var total = 0; var no_data = true; var tbl = document.createElement('table'); - tbl.setAttribute('class', 'trending_language_tbl'); + tbl.setAttribute('class', 'trending_language_tbl rctable'); $.each(data, function(key, val){ total += val.count; @@ -120,54 +120,47 @@ var showRepoStats = function(target, dat cnt += 1; no_data = false; - var hide = cnt > 2; var tr = document.createElement('tr'); - if (hide) { - tr.setAttribute('style', 'display:none'); - tr.setAttribute('class', 'stats_hidden'); - } var key = val[0]; var obj = {"desc": val[1].desc, "count": val[1].count}; - var percentage = Math.round((obj.count / total * 100), 2); - + // meta language names var td1 = document.createElement('td'); - td1.width = 300; var trending_language_label = document.createElement('div'); - trending_language_label.innerHTML = obj.desc + " (.{0})".format(key); + trending_language_label.innerHTML = obj.desc; td1.appendChild(trending_language_label); + // extensions var td2 = document.createElement('td'); - var trending_language = document.createElement('div'); - var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count); - - trending_language.title = key + " " + nr_files; + var extension = document.createElement('div'); + extension.innerHTML = ".{0}".format(key) + td2.appendChild(extension); - trending_language.innerHTML = "" + percentage + "% " + nr_files - + "" + percentage + "% " + nr_files + ""; + // number of files + var td3 = document.createElement('td'); + var file_count = document.createElement('div'); + var percentage_num = Math.round((obj.count / total * 100), 2); + var label = _ngettext('file', 'files', obj.count); + file_count.innerHTML = "{0} {1} ({2}%)".format(obj.count, label, percentage_num) ; + td3.appendChild(file_count); - trending_language.setAttribute("class", 'trending_language'); - $('b', trending_language)[0].style.width = percentage + "%"; - td2.appendChild(trending_language); + // percentage + var td4 = document.createElement('td'); + td4.setAttribute("class", 'trending_language'); + + var percentage = document.createElement('div'); + percentage.setAttribute('class', 'lang-bar'); + percentage.innerHTML = " "; + percentage.style.width = percentage_num + '%'; + td4.appendChild(percentage); tr.appendChild(td1); tr.appendChild(td2); + tr.appendChild(td3); + tr.appendChild(td4); tbl.appendChild(tr); - if (cnt == 3) { - var show_more = document.createElement('tr'); - var td = document.createElement('td'); - lnk = document.createElement('a'); - lnk.href = '#'; - lnk.innerHTML = _gettext('Show more'); - lnk.id = 'code_stats_show_more'; - td.appendChild(lnk); - - show_more.appendChild(td); - show_more.appendChild(document.createElement('td')); - tbl.appendChild(show_more); - } }); $(container).html(tbl); diff --git a/rhodecode/public/js/src/rhodecode/changelog.js b/rhodecode/public/js/src/rhodecode/changelog.js --- a/rhodecode/public/js/src/rhodecode/changelog.js +++ b/rhodecode/public/js/src/rhodecode/changelog.js @@ -46,6 +46,8 @@ var CommitsController = function () { self.$graphCanvas.html(''); var edgeData = $("[data-graph]").data('graph') || this.$graphCanvas.data('graph') || []; + var prev_link = $('.load-more-commits').find('.prev-commits').get(0); + var next_link = $('.load-more-commits').find('.next-commits').get(0); // Determine max number of edges per row in graph var edgeCount = 1; @@ -57,10 +59,20 @@ var CommitsController = function () { }); }); + if (prev_link && next_link) { + var graph_padding = -64; + } + else if (next_link) { + var graph_padding = -32; + } else { + var graph_padding = 0; + } + var x_step = Math.min(10, Math.floor(86 / edgeCount)); + var height = $('#changesets').find('.commits-range').height() + graph_padding; var graph_options = { width: 100, - height: $('#changesets').find('.commits-range').height(), + height: height, x_step: x_step, y_step: 42, dotRadius: 3.5, @@ -85,11 +97,11 @@ var CommitsController = function () { this.$graphCanvas.commits(graph_options); this.setLabelText(edgeData); - if ($('.load-more-commits').find('.prev-commits').get(0)) { - var padding = 75; - } else { - var padding = 43; + var padding = 90; + if (prev_link) { + padding += 34; + } $('#graph_nodes').css({'padding-top': padding}); }; @@ -112,10 +124,10 @@ var CommitsController = function () { } if (urlData['commit_id'] && urlData['f_path']) { - return pyroutes.url('repo_changelog_elements_file', urlData); + return pyroutes.url('repo_commits_elements_file', urlData); } else { - return pyroutes.url('repo_changelog_elements', urlData); + return pyroutes.url('repo_commits_elements', urlData); } }; diff --git a/rhodecode/public/js/src/rhodecode/codemirror.js b/rhodecode/public/js/src/rhodecode/codemirror.js --- a/rhodecode/public/js/src/rhodecode/codemirror.js +++ b/rhodecode/public/js/src/rhodecode/codemirror.js @@ -204,7 +204,12 @@ var CodeMirrorCompleteAfter = function(c }; var initCodeMirror = function(textAreadId, resetUrl, focus, options) { - var ta = $('#' + textAreadId).get(0); + if (textAreadId.substr(0,1) === "#"){ + var ta = $(textAreadId).get(0); + }else { + var ta = $('#' + textAreadId).get(0); + } + if (focus === undefined) { focus = true; } @@ -644,18 +649,6 @@ var fillCodeMirrorOptions = function(tar } }; -var CodeMirrorPreviewEnable = function(edit_mode) { - // in case it a preview enabled mode enable the button - if (['markdown', 'rst', 'gfm'].indexOf(edit_mode) !== -1) { - $('#render_preview').removeClass('hidden'); - } - else { - if (!$('#render_preview').hasClass('hidden')) { - $('#render_preview').addClass('hidden'); - } - } -}; - /* markup form */ (function(mod) { diff --git a/rhodecode/public/js/src/rhodecode/comments.js b/rhodecode/public/js/src/rhodecode/comments.js --- a/rhodecode/public/js/src/rhodecode/comments.js +++ b/rhodecode/public/js/src/rhodecode/comments.js @@ -587,12 +587,14 @@ var CommentsController = function() { $('#content').removeClass("wrapper"); $('#content').addClass("wide-mode-wrapper"); $(node).addClass('btn-success'); + return true } else { $('#content').removeClass("wide-mode-wrapper"); $('#content').addClass("wrapper"); $(node).removeClass('btn-success'); + return false } - return false; + }; this.toggleComments = function(node, show) { diff --git a/rhodecode/public/js/src/rhodecode/files.js b/rhodecode/public/js/src/rhodecode/files.js --- a/rhodecode/public/js/src/rhodecode/files.js +++ b/rhodecode/public/js/src/rhodecode/files.js @@ -19,234 +19,254 @@ /** * Search file list */ -// global reference to file-node filter -var _NODEFILTER = {}; + +var NodeFilter = {}; -var fileBrowserListeners = function(node_list_url, url_base){ - var n_filter = $('#node_filter').get(0); - - _NODEFILTER.filterTimeout = null; - var nodes = null; +var fileBrowserListeners = function (node_list_url, url_base) { + var $filterInput = $('#node_filter'); + var n_filter = $filterInput.get(0); - _NODEFILTER.fetchNodes = function(callback) { - $.ajax({url: node_list_url, headers: {'X-PARTIAL-XHR': true}}) - .done(function(data){ - nodes = data.nodes; - if (callback) { - callback(); - } - }) - .fail(function(data){ - console.log('failed to load'); - }); - }; + NodeFilter.filterTimeout = null; + var nodes = null; - _NODEFILTER.fetchNodesCallback = function() { - $('#node_filter_box_loading').hide(); - $('#node_filter_box').removeClass('hidden').show(); - n_filter.focus(); - if ($('#node_filter').hasClass('init')){ - n_filter.value = ''; - $('#node_filter').removeClass('init'); - } - }; + NodeFilter.focus = function () { + $filterInput.focus() + }; - _NODEFILTER.initFilter = function(){ - $('#node_filter_box_loading').removeClass('hidden').show(); - $('#search_activate_id').hide(); - $('#search_deactivate_id').removeClass('hidden').show(); - $('#add_node_id').hide(); - _NODEFILTER.fetchNodes(_NODEFILTER.fetchNodesCallback); - }; + NodeFilter.fetchNodes = function (callback) { + $.ajax( + {url: node_list_url, headers: {'X-PARTIAL-XHR': true}}) + .done(function (data) { + nodes = data.nodes; + if (callback) { + callback(); + } + }) + .fail(function (data) { + console.log('failed to load'); + }); + }; - _NODEFILTER.resetFilter = function(){ - $('#node_filter_box_loading').hide(); - $('#node_filter_box').hide(); - $('#search_activate_id').show(); - $('#search_deactivate_id').hide(); - $('#add_node_id').show(); - $('#tbody').show(); - $('#tbody_filtered').hide(); - $('#node_filter').val(''); - }; - - _NODEFILTER.fuzzy_match = function(filepath, query) { - var highlight = []; - var order = 0; - for (var i = 0; i < query.length; i++) { - var match_position = filepath.indexOf(query[i]); - if (match_position !== -1) { - var prev_match_position = highlight[highlight.length-1]; - if (prev_match_position === undefined) { - highlight.push(match_position); - } else { - var current_match_position = prev_match_position + match_position + 1; - highlight.push(current_match_position); - order = order + current_match_position - prev_match_position; + NodeFilter.initFilter = function (e) { + if ($filterInput.hasClass('loading')) { + return } - filepath = filepath.substring(match_position+1); - } else { - return false; - } - } - return {'order': order, - 'highlight': highlight}; - }; - _NODEFILTER.sortPredicate = function(a, b) { - if (a.order < b.order) return -1; - if (a.order > b.order) return 1; - if (a.filepath < b.filepath) return -1; - if (a.filepath > b.filepath) return 1; - return 0; - }; - - _NODEFILTER.updateFilter = function(elem, e) { - return function(){ - // Reset timeout - _NODEFILTER.filterTimeout = null; - var query = elem.value.toLowerCase(); - var match = []; - var matches_max = 20; - if (query !== ""){ - var results = []; - for(var k=0;k 0){ - var n = results[i].filepath; - var t = results[i].type; - var n_hl = n.split(""); - var pos = results[i].highlight; - for (var j = 0; j < pos.length; j++) { - n_hl[pos[j]] = "" + n_hl[pos[j]] + ""; - } - n_hl = n_hl.join(""); - var new_url = url_base.replace('__FPATH__',n); + var iconLoading = 'icon-spin animate-spin'; + var iconSearch = 'icon-search'; + $('.files-filter-box-path i').removeClass(iconSearch).addClass(iconLoading); + $filterInput.addClass('loading'); - var typeObj = { - dir: 'icon-directory browser-dir', - file: 'icon-file-text browser-file' - }; + var callback = function (org) { + return function () { + if ($filterInput.hasClass('init')) { + $filterInput.removeClass('init'); + $filterInput.removeClass('loading'); + } + $('.files-filter-box-path i').removeClass(iconLoading).addClass(iconSearch); - var typeIcon = ''.format(typeObj[t]); - match.push('{1}{2}'.format(new_url,typeIcon, n_hl)); - } - } - if(results.length > limit){ - var truncated_count = results.length - matches_max; - if (truncated_count === 1) { - match.push('{0} {1}'.format(truncated_count, _gettext('truncated result'))); - } else { - match.push('{0} {1}'.format(truncated_count, _gettext('truncated results'))); - } - } - } - if (query !== ""){ - $('#tbody').hide(); - $('#tbody_filtered').show(); + // auto re-filter if we filled in the input + if (n_filter.value !== "") { + NodeFilter.updateFilter(n_filter, e)() + } - if (match.length === 0){ - match.push('{0}'.format(_gettext('No matching files'))); - } - $('#tbody_filtered').html(match.join("")); - } - else{ + } + }; + // load node data + NodeFilter.fetchNodes(callback()); + + }; + + NodeFilter.resetFilter = function () { $('#tbody').show(); $('#tbody_filtered').hide(); - } + $filterInput.val(''); + }; + + NodeFilter.handleKey = function (e) { + var scrollDown = function (element) { + var elementBottom = element.offset().top + $(element).outerHeight(); + var windowBottom = window.innerHeight + $(window).scrollTop(); + if (elementBottom > windowBottom) { + var offset = elementBottom - window.innerHeight; + $('html,body').scrollTop(offset); + return false; + } + return true; + }; + + var scrollUp = function (element) { + if (element.offset().top < $(window).scrollTop()) { + $('html,body').scrollTop(element.offset().top); + return false; + } + return true; + }; + var $hlElem = $('.browser-highlight'); + + if (e.keyCode === 40) { // Down + if ($hlElem.length === 0) { + $('.browser-result').first().addClass('browser-highlight'); + } else { + var next = $hlElem.next(); + if (next.length !== 0) { + $hlElem.removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } + + if ($hlElem.get(0) !== undefined){ + scrollDown($hlElem); + } + } + if (e.keyCode === 38) { // Up + e.preventDefault(); + if ($hlElem.length !== 0) { + var next = $hlElem.prev(); + if (next.length !== 0) { + $('.browser-highlight').removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } + + if ($hlElem.get(0) !== undefined){ + scrollUp($hlElem); + } + + } + if (e.keyCode === 13) { // Enter + if ($('.browser-highlight').length !== 0) { + var url = $('.browser-highlight').find('.match-link').attr('href'); + window.location = url; + } + } + if (e.keyCode === 27) { // Esc + NodeFilter.resetFilter(); + $('html,body').scrollTop(0); + } + + var capture_keys = [ + 40, // ArrowDown + 38, // ArrowUp + 39, // ArrowRight + 37, // ArrowLeft + 13, // Enter + 27 // Esc + ]; + + if ($.inArray(e.keyCode, capture_keys) === -1) { + clearTimeout(NodeFilter.filterTimeout); + NodeFilter.filterTimeout = setTimeout(NodeFilter.updateFilter(n_filter, e), 200); + } }; - }; - - var scrollDown = function(element){ - var elementBottom = element.offset().top + $(element).outerHeight(); - var windowBottom = window.innerHeight + $(window).scrollTop(); - if (elementBottom > windowBottom) { - var offset = elementBottom - window.innerHeight; - $('html,body').scrollTop(offset); - return false; - } - return true; - }; - var scrollUp = function(element){ - if (element.offset().top < $(window).scrollTop()) { - $('html,body').scrollTop(element.offset().top); - return false; - } - return true; - }; + NodeFilter.fuzzy_match = function (filepath, query) { + var highlight = []; + var order = 0; + for (var i = 0; i < query.length; i++) { + var match_position = filepath.indexOf(query[i]); + if (match_position !== -1) { + var prev_match_position = highlight[highlight.length - 1]; + if (prev_match_position === undefined) { + highlight.push(match_position); + } else { + var current_match_position = prev_match_position + match_position + 1; + highlight.push(current_match_position); + order = order + current_match_position - prev_match_position; + } + filepath = filepath.substring(match_position + 1); + } else { + return false; + } + } + return { + 'order': order, + 'highlight': highlight + }; + }; - $('#filter_activate').click(function() { - _NODEFILTER.initFilter(); - }); - - $('#filter_deactivate').click(function() { - _NODEFILTER.resetFilter(); - }); - - $(n_filter).click(function() { - if ($('#node_filter').hasClass('init')){ - n_filter.value = ''; - $('#node_filter').removeClass('init'); - } - }); + NodeFilter.sortPredicate = function (a, b) { + if (a.order < b.order) return -1; + if (a.order > b.order) return 1; + if (a.filepath < b.filepath) return -1; + if (a.filepath > b.filepath) return 1; + return 0; + }; - $(n_filter).keydown(function(e) { - if (e.keyCode === 40){ // Down - if ($('.browser-highlight').length === 0){ - $('.browser-result').first().addClass('browser-highlight'); - } else { - var next = $('.browser-highlight').next(); - if (next.length !== 0) { - $('.browser-highlight').removeClass('browser-highlight'); - next.addClass('browser-highlight'); - } - } - scrollDown($('.browser-highlight')); - } - if (e.keyCode === 38){ // Up - e.preventDefault(); - if ($('.browser-highlight').length !== 0){ - var next = $('.browser-highlight').prev(); - if (next.length !== 0) { - $('.browser-highlight').removeClass('browser-highlight'); - next.addClass('browser-highlight'); - } - } - scrollUp($('.browser-highlight')); - } - if (e.keyCode === 13){ // Enter - if ($('.browser-highlight').length !== 0){ - var url = $('.browser-highlight').find('.pjax-link').attr('href'); - $.pjax({url: url, container: '#pjax-container', timeout: pjaxTimeout}); - } - } - if (e.keyCode === 27){ // Esc - _NODEFILTER.resetFilter(); - $('html,body').scrollTop(0); - } - }); - var capture_keys = [40, 38, 39, 37, 13, 27]; - $(n_filter).keyup(function(e) { - if ($.inArray(e.keyCode, capture_keys) === -1){ - clearTimeout(_NODEFILTER.filterTimeout); - _NODEFILTER.filterTimeout = setTimeout(_NODEFILTER.updateFilter(n_filter, e),200); - } - }); + NodeFilter.updateFilter = function (elem, e) { + return function () { + // Reset timeout + NodeFilter.filterTimeout = null; + var query = elem.value.toLowerCase(); + var match = []; + var matches_max = 20; + if (query !== "") { + var results = []; + for (var k = 0; k < nodes.length; k++) { + var result = NodeFilter.fuzzy_match( + nodes[k].name.toLowerCase(), query); + if (result) { + result.type = nodes[k].type; + result.filepath = nodes[k].name; + results.push(result); + } + } + results = results.sort(NodeFilter.sortPredicate); + var limit = matches_max; + if (results.length < matches_max) { + limit = results.length; + } + for (var i = 0; i < limit; i++) { + if (query && results.length > 0) { + var n = results[i].filepath; + var t = results[i].type; + var n_hl = n.split(""); + var pos = results[i].highlight; + for (var j = 0; j < pos.length; j++) { + n_hl[pos[j]] = "" + n_hl[pos[j]] + ""; + } + n_hl = n_hl.join(""); + var new_url = url_base.replace('__FPATH__', n); + + var typeObj = { + dir: 'icon-directory browser-dir', + file: 'icon-file-text browser-file' + }; + + var typeIcon = ''.format(typeObj[t]); + match.push('{1}{2}'.format(new_url, typeIcon, n_hl)); + } + } + if (results.length > limit) { + var truncated_count = results.length - matches_max; + if (truncated_count === 1) { + match.push('{0} {1}'.format(truncated_count, _gettext('truncated result'))); + } else { + match.push('{0} {1}'.format(truncated_count, _gettext('truncated results'))); + } + } + } + if (query !== "") { + $('#tbody').hide(); + $('#tbody_filtered').show(); + + if (match.length === 0) { + match.push('{0}'.format(_gettext('No matching files'))); + } + $('#tbody_filtered').html(match.join("")); + } else { + $('#tbody').show(); + $('#tbody_filtered').hide(); + } + + }; + }; + }; var getIdentNode = function(n){ @@ -308,3 +328,190 @@ var getSelectionLink = function(e) { } } }; + +var getFileState = function() { + // relies on a global set filesUrlData + var f_path = filesUrlData['f_path']; + var commit_id = filesUrlData['commit_id']; + + var url_params = { + repo_name: templateContext.repo_name, + commit_id: commit_id, + f_path:'__FPATH__' + }; + if (atRef !== '') { + url_params['at'] = atRef + } + + var _url_base = pyroutes.url('repo_files', url_params); + var _node_list_url = pyroutes.url('repo_files_nodelist', + {repo_name: templateContext.repo_name, + commit_id: commit_id, f_path: f_path}); + + return { + f_path: f_path, + commit_id: commit_id, + node_list_url: _node_list_url, + url_base: _url_base + }; +}; + +var getFilesMetadata = function() { + // relies on metadataRequest global state + if (metadataRequest && metadataRequest.readyState != 4) { + metadataRequest.abort(); + } + + if ($('#file-tree-wrapper').hasClass('full-load')) { + // in case our HTML wrapper has full-load class we don't + // trigger the async load of metadata + return false; + } + + var state = getFileState(); + var url_data = { + 'repo_name': templateContext.repo_name, + 'commit_id': state.commit_id, + 'f_path': state.f_path + }; + + var url = pyroutes.url('repo_nodetree_full', url_data); + + metadataRequest = $.ajax({url: url}); + + metadataRequest.done(function(data) { + $('#file-tree').html(data); + timeagoActivate(); + }); + metadataRequest.fail(function (data, textStatus, errorThrown) { + if (data.status != 0) { + alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText)); + } + }); +}; + +// show more authors +var showAuthors = function(elem, annotate) { + var state = getFileState('callbacks'); + + var url = pyroutes.url('repo_file_authors', + {'repo_name': templateContext.repo_name, + 'commit_id': state.commit_id, 'f_path': state.f_path}); + + $.pjax({ + url: url, + data: 'annotate={0}'.format(annotate), + container: '#file_authors', + push: false, + timeout: 5000 + }).complete(function(){ + $(elem).hide(); + $('#file_authors_title').html(_gettext('All Authors')) + }) +}; + + +(function (mod) { + + if (typeof exports == "object" && typeof module == "object") { + // CommonJS + module.exports = mod(); + } else { + // Plain browser env + (this || window).FileEditor = mod(); + } + +})(function () { + "use strict"; + + function FileEditor(textAreaElement, options) { + if (!(this instanceof FileEditor)) { + return new FileEditor(textAreaElement, options); + } + // bind the element instance to our Form + var te = $(textAreaElement).get(0); + if (te !== undefined) { + te.FileEditor = this; + } + + this.modes_select = '#set_mode'; + this.filename_selector = '#filename'; + this.commit_btn_selector = '#commit_btn'; + this.line_wrap_selector = '#line_wrap'; + this.editor_preview_selector = '#editor_preview'; + + if (te !== undefined) { + this.cm = initCodeMirror(textAreaElement, null, false); + } + + // FUNCTIONS and helpers + var self = this; + + this.submitHandler = function() { + $(self.commit_btn_selector).on('click', function(e) { + + var filename = $(self.filename_selector).val(); + if (filename === "") { + alert("Missing filename"); + e.preventDefault(); + } + + var button = $(this); + if (button.hasClass('clicked')) { + button.attr('disabled', true); + } else { + button.addClass('clicked'); + } + }); + }; + this.submitHandler(); + + // on select line wraps change the editor + this.lineWrapHandler = function () { + $(self.line_wrap_selector).on('change', function (e) { + var selected = e.currentTarget; + var line_wraps = {'on': true, 'off': false}[selected.value]; + setCodeMirrorLineWrap(self.cm, line_wraps) + }); + }; + this.lineWrapHandler(); + + + this.showPreview = function () { + + var _text = self.cm.getValue(); + var _file_path = $(self.filename_selector).val(); + if (_text && _file_path) { + $('.show-preview').addClass('active'); + $('.show-editor').removeClass('active'); + + $(self.editor_preview_selector).show(); + $(self.cm.getWrapperElement()).hide(); + + + var post_data = {'text': _text, 'file_path': _file_path, 'csrf_token': CSRF_TOKEN}; + $(self.editor_preview_selector).html(_gettext('Loading ...')); + + var url = pyroutes.url('file_preview'); + + ajaxPOST(url, post_data, function (o) { + $(self.editor_preview_selector).html(o); + }) + } + + }; + + this.showEditor = function () { + $(self.editor_preview_selector).hide(); + $('.show-editor').addClass('active'); + $('.show-preview').removeClass('active'); + + $(self.cm.getWrapperElement()).show(); + }; + + + } + + return FileEditor; +}); + diff --git a/rhodecode/public/js/src/rhodecode/followers.js b/rhodecode/public/js/src/rhodecode/followers.js --- a/rhodecode/public/js/src/rhodecode/followers.js +++ b/rhodecode/public/js/src/rhodecode/followers.js @@ -16,58 +16,44 @@ // # RhodeCode Enterprise Edition, including its added features, Support services, // # and proprietary license terms, please see https://rhodecode.com/licenses/ -var onSuccessFollow = function(target){ - var f = $(target); - var f_cnt = $('#current_followers_count'); +var onSuccessFollow = function (target) { + var targetEl = $(target); - if(f.hasClass('follow')){ - f.removeClass('follow'); - f.addClass('following'); - f.attr('title', _gettext('Stop following this repository')); - $(f).html(_gettext('Unfollow')); - if(f_cnt.length){ - var cnt = Number(f_cnt.html())+1; - f_cnt.html(cnt); + var callback = function () { + targetEl.animate({'opacity': 1.00}, 200); + if (targetEl.hasClass('watching')) { + targetEl.removeClass('watching'); + targetEl.attr('title', _gettext('Stopped watching this repository')); + $(targetEl).html(''+_gettext('Watch')); + } else { + targetEl.addClass('watching'); + targetEl.attr('title', _gettext('Started watching this repository')); + $(targetEl).html(''+_gettext('Unwatch')); } - } - else{ - f.removeClass('following'); - f.addClass('follow'); - f.attr('title', _gettext('Start following this repository')); - $(f).html(_gettext('Follow')); - if(f_cnt.length){ - var cnt = Number(f_cnt.html())-1; - f_cnt.html(cnt); - } - } + }; + targetEl.animate({'opacity': 0.15}, 200, callback); }; -// TODO:: check if the function is needed. 0 usage found -var toggleFollowingUser = function(target,follows_user_id,token,user_id){ + +var toggleFollowingUser = function (target, follows_user_id) { var args = { 'follows_user_id': follows_user_id, - 'auth_token': token, 'csrf_token': CSRF_TOKEN }; - if(user_id != undefined){ - args.user_id = user_id - } - ajaxPOST(pyroutes.url('toggle_following'), args, function(){ + + ajaxPOST(pyroutes.url('toggle_following'), args, function () { onSuccessFollow(target); }); return false; }; -var toggleFollowingRepo = function(target,follows_repo_id,token,user_id){ +var toggleFollowingRepo = function (target, follows_repo_id) { var args = { 'follows_repo_id': follows_repo_id, - 'auth_token': token, 'csrf_token': CSRF_TOKEN }; - if(user_id != undefined){ - args.user_id = user_id - } - ajaxPOST(pyroutes.url('toggle_following'), args, function(){ + + ajaxPOST(pyroutes.url('toggle_following'), args, function () { onSuccessFollow(target); }); return false; diff --git a/rhodecode/public/js/src/rhodecode/select2_widgets.js b/rhodecode/public/js/src/rhodecode/select2_widgets.js --- a/rhodecode/public/js/src/rhodecode/select2_widgets.js +++ b/rhodecode/public/js/src/rhodecode/select2_widgets.js @@ -73,10 +73,3 @@ var select2RefSwitcher = function(target {'repo_name': templateContext.repo_name}); select2RefBaseSwitcher(targetElement, loadUrl, initialData); }; - -var select2FileHistorySwitcher = function(targetElement, initialData, state) { - var loadUrl = pyroutes.url('repo_file_history', - {'repo_name': templateContext.repo_name, 'commit_id': state.rev, - 'f_path': state.f_path}); - select2RefBaseSwitcher(targetElement, loadUrl, initialData); -}; diff --git a/rhodecode/templates/admin/admin_audit_log_entry.mako b/rhodecode/templates/admin/admin_audit_log_entry.mako --- a/rhodecode/templates/admin/admin_audit_log_entry.mako +++ b/rhodecode/templates/admin/admin_audit_log_entry.mako @@ -9,20 +9,23 @@ %endif -<%def name="breadcrumbs_links()"> - ${_('Audit long entry')} ${c.audit_log_entry.entry_id} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_nav()"> ${self.menu_items(active='admin')} + +<%def name="menu_bar_subnav()"> + ${self.admin_menu(active='audit_logs')} + + <%def name="main()">
- +
- ${self.breadcrumbs()} + ${_('Audit long entry')} ${c.audit_log_entry.entry_id}
- +
diff --git a/rhodecode/templates/admin/admin_audit_logs.mako b/rhodecode/templates/admin/admin_audit_logs.mako --- a/rhodecode/templates/admin/admin_audit_logs.mako +++ b/rhodecode/templates/admin/admin_audit_logs.mako @@ -8,27 +8,28 @@ %endif -<%def name="breadcrumbs_links()"> - ${h.form(None, id_="filter_form", method="get")} - - - ${_('Audit logs')} - ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)} - ${h.end_form()} -

${_('Example Queries')}

- - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_nav()"> ${self.menu_items(active='admin')} +<%def name="menu_bar_subnav()"> + ${self.admin_menu(active='audit_logs')} + + <%def name="main()">
-
- ${self.breadcrumbs()} + ${h.form(None, id_="filter_form", method="get")} + + + ${_('Audit logs')} - ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)} + ${h.end_form()} +

${_('Example Queries')}

+
- +
<%include file="/admin/admin_log_base.mako" /> diff --git a/rhodecode/templates/admin/auth/auth_settings.mako b/rhodecode/templates/admin/auth/auth_settings.mako --- a/rhodecode/templates/admin/auth/auth_settings.mako +++ b/rhodecode/templates/admin/auth/auth_settings.mako @@ -8,29 +8,26 @@ %endif -<%def name="breadcrumbs_links()"> - ${h.link_to(_('Admin'),h.route_path('admin_home'))} - » - ${_('Authentication Plugins')} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_nav()"> ${self.menu_items(active='admin')} +<%def name="menu_bar_subnav()"> + ${self.admin_menu(active='authentication')} + + <%def name="main()">
-
- ${self.breadcrumbs()} -
%for plugin in available_plugins: - + diff --git a/rhodecode/templates/admin/auth/plugin_settings.mako b/rhodecode/templates/admin/auth/plugin_settings.mako --- a/rhodecode/templates/admin/auth/plugin_settings.mako +++ b/rhodecode/templates/admin/auth/plugin_settings.mako @@ -2,10 +2,10 @@ <%inherit file="/base/base.mako"/> <%def name="title()"> - ${_('Authentication Settings')} - %if c.rhodecode_name: + ${_('Authentication Settings')} + %if c.rhodecode_name: · ${h.branding(c.rhodecode_name)}} - %endif + %endif <%def name="breadcrumbs_links()"> @@ -17,22 +17,23 @@ <%def name="menu_bar_nav()"> - ${self.menu_items(active='admin')} + ${self.menu_items(active='admin')} + + +<%def name="menu_bar_subnav()"> + ${self.admin_menu(active='authentication')} <%def name="main()"> +
-
- ${self.breadcrumbs()} -
+
${_('Plugin ID')} ${_('Enabled')}
- - ${_('activated') if plugin.get_id() in enabled_plugins else _('not active')} + + ${(_('activated') if plugin.get_id() in enabled_plugins else _('not active'))} ${plugin.get_display_name()}
-
+ -
-
- ${self.repo_page_title(c.rhodecode_db_repo)} -
-
- +
-
- - ${_('parent')} - - | - - ${_('child')} - -
-
+ +
-
- ${_('Description')}: -
-
-
${h.urlify_commit_message(c.commit.message,c.repo_name)}
- %if c.statuses:
-
- ${_('Commit status')}: -
-
-
-
+
+

${_('Commit status')}:

+
+
+
+
+
[${h.commit_status_lbl(c.statuses[0])}]
-
[${h.commit_status_lbl(c.statuses[0])}]
%endif
-
- ${_('References')}: -
-
-
- - %if c.commit.merge: - - ${_('merge')} - - %endif +
+

${_('References')}:

+
+
+ %if c.commit.merge: + + ${_('merge')} + + %endif - %if h.is_hg(c.rhodecode_repo): - %for book in c.commit.bookmarks: - - ${h.shorter(book)} - - %endfor - %endif + %if h.is_hg(c.rhodecode_repo): + %for book in c.commit.bookmarks: + + ${h.shorter(book)} + + %endfor + %endif - %for tag in c.commit.tags: - - ${tag} - - %endfor + %for tag in c.commit.tags: + + ${tag} + + %endfor - %if c.commit.branch: - - ${h.shorter(c.commit.branch)} - - %endif + %if c.commit.branch: + + ${h.shorter(c.commit.branch)} + + %endif +
-
+
-
- ${_('Diff options')}: -
-
-
- ${_('Comments')}: -
-
+
+

${_('Comments')}:

+
%if c.comments: ${_ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}, @@ -171,40 +169,42 @@ ${_ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} %endif
+
-
- ${_('Unresolved TODOs')}: -
-
-
- % if c.unresolved_comments: - % for co in c.unresolved_comments: - ${'' if loop.last else ','} - % endfor - % else: - ${_('There are no unresolved TODOs')} - % endif -
+
+

${_('Unresolved TODOs')}:

+
+
+ % if c.unresolved_comments: + % for co in c.unresolved_comments: + ${'' if loop.last else ','} + % endfor + % else: + ${_('There are no unresolved TODOs')} + % endif +
+
-
+
+
+

${_('Author')}

- + +
+ +
+
<%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/> ${cbdiffs.render_diffset_menu(c.changes[c.commit.raw_id])} diff --git a/rhodecode/templates/changeset/changeset_file_comment.mako b/rhodecode/templates/changeset/changeset_file_comment.mako --- a/rhodecode/templates/changeset/changeset_file_comment.mako +++ b/rhodecode/templates/changeset/changeset_file_comment.mako @@ -139,7 +139,7 @@ ## only super-admin, repo admin OR comment owner can delete, also hide delete if currently viewed comment is outdated %if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())): ## permissions to delete - %if h.HasPermissionAny('hg.admin')() or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: + %if c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: ## TODO: dan: add edit comment here ${_('Delete')} %else: diff --git a/rhodecode/templates/changeset/changeset_range.mako b/rhodecode/templates/changeset/changeset_range.mako --- a/rhodecode/templates/changeset/changeset_range.mako +++ b/rhodecode/templates/changeset/changeset_range.mako @@ -12,67 +12,76 @@ %endif -<%def name="breadcrumbs_links()"> - ${_('Commits')} - - r${c.commit_ranges[0].idx}:${h.short_id(c.commit_ranges[0].raw_id)} - ... - r${c.commit_ranges[-1].idx}:${h.short_id(c.commit_ranges[-1].raw_id)} - ${_ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_nav()"> ${self.menu_items(active='repositories')} <%def name="menu_bar_subnav()"> - ${self.repo_menu(active='changelog')} + ${self.repo_menu(active='commits')} <%def name="main()"> -
-
- ${self.repo_page_title(c.rhodecode_db_repo)} -
-
- +
+
+
+
+ +

+ ${_('Commit Range')} +

+
-
-
-
- -

- ${_('Commit Range')} - - r${c.commit_ranges[0].idx}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].idx}:${h.short_id(c.commit_ranges[-1].raw_id)} - -

-
-
+
+
-
-
- ${_('Diff option')}: -
-
-
- - ${_('Show combined compare')} - +
+
+

${_('Range')}:

+
+
+
+ + r${c.commit_ranges[0].idx}:${h.short_id(c.commit_ranges[0].raw_id)} + ... + r${c.commit_ranges[-1].idx}:${h.short_id(c.commit_ranges[-1].raw_id)} + ${_ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} + +
+
+
+
-
-
-
+
+
+

${_('Diff Option')}:

+ +
+
-
+
+
+
-
+
+ diff --git a/rhodecode/templates/codeblocks/diffs.mako b/rhodecode/templates/codeblocks/diffs.mako --- a/rhodecode/templates/codeblocks/diffs.mako +++ b/rhodecode/templates/codeblocks/diffs.mako @@ -959,7 +959,8 @@ def get_comments_for(diff_type, comments text: _gettext('Toggle Wide Mode diff'), action: function () { updateSticky(); - Rhodecode.comments.toggleWideMode(this); + var wide = Rhodecode.comments.toggleWideMode(this); + storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide); return null; }, url: null, @@ -1002,6 +1003,11 @@ def get_comments_for(diff_type, comments ] }; + // get stored diff mode and pre-enable it + if (templateContext.session_attrs.wide_diff_mode === "true") { + Rhodecode.comments.toggleWideMode(null); + } + $("#diff_menu").select2({ minimumResultsForSearch: -1, containerCssClass: "drop-menu", diff --git a/rhodecode/templates/changelog/changelog.mako b/rhodecode/templates/commits/changelog.mako rename from rhodecode/templates/changelog/changelog.mako rename to rhodecode/templates/commits/changelog.mako --- a/rhodecode/templates/changelog/changelog.mako +++ b/rhodecode/templates/commits/changelog.mako @@ -23,17 +23,36 @@ <%def name="menu_bar_subnav()"> - ${self.repo_menu(active='changelog')} + ${self.repo_menu(active='commits')} <%def name="main()">
+ @@ -74,29 +88,7 @@
-
- ${h.hidden('branch_filter')} - %if c.selected_name: -
- ${_('Clear filter')} -
- %endif -
${self.breadcrumbs('breadcrumbs_light')} -
-
- ${_ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)} -
@@ -104,18 +96,21 @@
-
+
## checkbox - - + - - ## Mercurial phase/evolve state - ## commit message expand arrow @@ -124,6 +119,8 @@ + ## comments + @@ -135,6 +132,9 @@
${c.pagination.pager('$link_previous ~2~ $link_next')}
+
+ ${_ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)} +
-
- ${self.repo_page_title(c.rhodecode_db_repo)} -
-
@@ -43,24 +37,24 @@

${_('Compare Commits')} % if c.file_path: - ${_('for file')} ${c.file_path} + ${_('for file')} ${c.file_path} % endif % if c.commit_ranges: - r${c.source_commit.idx}:${h.short_id(c.source_commit.raw_id)}...r${c.target_commit.idx}:${h.short_id(c.target_commit.raw_id)} + r${c.commit_ranges[0].idx}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].idx}:${h.short_id(c.commit_ranges[-1].raw_id)} % endif

+ +
-
- ${_('Target')}: -
-
-
+
+

${_('Target')}:

+
## The hidden elements are replaced with a select2 widget @@ -72,11 +66,9 @@
-
- ${_('Source')}: -
-
-
+
+

${_('Source')}:

+
## The hidden elements are replaced with a select2 widget @@ -88,17 +80,29 @@
-
- ${_('Actions')}: -
-
-
+
+

${_('Actions')}:

+
-
% if c.compare_home: ${_('Compare Commits')} + %if c.rhodecode_db_repo.fork: + + + ${_('Compare with origin')} + + + %endif ${_('Swap')} ${_('Comment')} @@ -126,31 +130,31 @@
-
+
## commit status form @@ -275,8 +279,6 @@ ## table diff data
- - % if not c.compare_home:
diff --git a/rhodecode/templates/data_table/_dt_elements.mako b/rhodecode/templates/data_table/_dt_elements.mako --- a/rhodecode/templates/data_table/_dt_elements.mako +++ b/rhodecode/templates/data_table/_dt_elements.mako @@ -48,8 +48,8 @@
  • - - ${_('Changelog')} + + ${_('Commits')}
  • @@ -205,7 +205,7 @@ <%def name="repo_group_name(repo_group_name, children_groups=None)">
    - + %if children_groups: ${h.literal(' » '.join(children_groups))} %else: @@ -377,6 +377,30 @@ +## ARTIFACT RENDERERS + +<%def name="repo_artifact_uid(repo_name, file_uid)"> + ${file_uid} + + +<%def name="repo_artifact_uid_action(repo_name, file_uid)"> + + + +<%def name="repo_artifact_actions(repo_name, file_store_id, file_uid)"> +##
    +## ${_('Edit')} +##
    +% if h.HasRepoPermissionAny('repository.admin')(c.repo_name): +
    + ${h.secure_form(h.route_path('repo_artifacts_delete', repo_name=repo_name, uid=file_store_id), request=request)} + ${h.submit('remove_',_('Delete'),id="remove_artifact_%s" % file_store_id, class_="btn btn-link btn-danger", + onclick="return confirm('"+_('Confirm to delete this artifact: %s') % file_uid+"');")} + ${h.end_form()} +
    +% endif + + <%def name="markup_form(form_id, form_text='', help_text=None)">
    diff --git a/rhodecode/templates/debug_style/code-block.html b/rhodecode/templates/debug_style/code-block.html --- a/rhodecode/templates/debug_style/code-block.html +++ b/rhodecode/templates/debug_style/code-block.html @@ -641,7 +641,7 @@ File Edit 1.2 KiB text/x-python
    - + history diff --git a/rhodecode/templates/debug_style/tables.html b/rhodecode/templates/debug_style/tables.html --- a/rhodecode/templates/debug_style/tables.html +++ b/rhodecode/templates/debug_style/tables.html @@ -425,7 +425,7 @@
  • - + diff --git a/rhodecode/templates/files/base.mako b/rhodecode/templates/files/base.mako --- a/rhodecode/templates/files/base.mako +++ b/rhodecode/templates/files/base.mako @@ -1,4 +1,11 @@ <%def name="refs(commit)"> + ## Build a cache of refs for selector + + %if commit.merge: ${_('merge')} @@ -10,6 +17,9 @@ ${h.shorter(book)} + %endfor %endif @@ -17,12 +27,18 @@ ${tag} + %endfor %if commit.branch: ${h.shorter(commit.branch)} + %endif diff --git a/rhodecode/templates/files/file_authors_box.mako b/rhodecode/templates/files/file_authors_box.mako --- a/rhodecode/templates/files/file_authors_box.mako +++ b/rhodecode/templates/files/file_authors_box.mako @@ -1,42 +1,38 @@ <%namespace name="base" file="/base/base.mako"/> -
    -

    - % if c.file_author: - ${_('Last Author')} - % else: - ${h.literal(_ungettext(u'File Author (%s)',u'File Authors (%s)',len(c.authors)) % ('%s' % len(c.authors))) } - % endif -

    - ${_('Show All')} -
    +% if c.authors: + +
    + ## clear selection + + + + ${_('Commit')} ${_('Commit Message')}${_('Author')} ${_('Refs')}
    td-active Shows active state with icon-true/icon-false.
    td-size
    + % for email, user, commits in sorted(c.authors, key=lambda e: c.file_last_commit.author_email!=e[0]): + -% if c.authors: - + + - - % endfor - + % endif + diff --git a/rhodecode/templates/files/file_content.mako b/rhodecode/templates/files/file_content.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/file_content.mako @@ -0,0 +1,9 @@ +<%namespace name="sourceblock" file="/codeblocks/source.mako"/> + +<%def name="render_lines(lines)"> + + %for line_num, tokens in enumerate(lines, 1): + ${sourceblock.render_line(line_num, tokens)} + %endfor +
    + diff --git a/rhodecode/templates/files/file_tree_author_box.mako b/rhodecode/templates/files/file_tree_author_box.mako deleted file mode 100644 --- a/rhodecode/templates/files/file_tree_author_box.mako +++ /dev/null @@ -1,12 +0,0 @@ -<%namespace name="base" file="/base/base.mako"/> - -
    -

    - ${_('Commit Author')} -

    -
    - - diff --git a/rhodecode/templates/files/files.mako b/rhodecode/templates/files/files.mako --- a/rhodecode/templates/files/files.mako +++ b/rhodecode/templates/files/files.mako @@ -1,9 +1,9 @@ <%inherit file="/base/base.mako"/> <%def name="title(*args)"> - ${_('%s Files') % c.repo_name} + ${_('{} Files').format(c.repo_name)} %if hasattr(c,'file'): - · ${h.safe_unicode(c.file.path) or '\\'} + · ${(h.safe_unicode(c.file.path) or '\\')} %endif %if c.rhodecode_name: @@ -27,113 +27,321 @@ <%def name="main()"> -
    - ${self.repo_page_title(c.rhodecode_db_repo)} -
    + + +
    <%include file='files_pjax.mako'/>
    - - + \ No newline at end of file diff --git a/rhodecode/templates/files/files_add.mako b/rhodecode/templates/files/files_add.mako --- a/rhodecode/templates/files/files_add.mako +++ b/rhodecode/templates/files/files_add.mako @@ -1,7 +1,7 @@ <%inherit file="/base/base.mako"/> <%def name="title()"> - ${_('%s Files Add') % c.repo_name} + ${_('{} Files Add').format(c.repo_name)} %if c.rhodecode_name: · ${h.branding(c.rhodecode_name)} %endif @@ -11,79 +11,64 @@ ${self.menu_items(active='repositories')} -<%def name="breadcrumbs_links()"> - ${_('Add new file')} @ ${h.show_id(c.commit)} ${_('Branch')}: ${c.commit.branch} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_subnav()"> ${self.repo_menu(active='files')} <%def name="main()"> +
    -
    - ${self.repo_page_title(c.rhodecode_db_repo)} + +
    + ${_('Add new file')} @ ${h.show_id(c.commit)} + % if c.commit.branch: + + ${c.commit.branch} + + % endif
    -
    - ${self.breadcrumbs()} -
    - ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', enctype="multipart/form-data", class_="form-horizontal", request=request)} + + ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
    -
    -
    - ${_('Path')}: -
    -
    -
    - ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} - ${_('Specify Custom Path')} +
    +
    + +
  • + +
  • +
    -
    -
    - ${_('Filename')}: -
    -
    - -

    ${_('or')} ${_('Upload File')}

    -
    -
    -
    +
    +
    -
    -
    - ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)} - - ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])} +
    +
    + ${_('Edit')} +
    + +
    + ${_('Preview')} +
    - +
    + ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off'))], extra_classes=['last-item'])} +
    +
    + ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))], enable_filter=True)} +
    -
    +
    
                         
    @@ -95,144 +80,35 @@
     
         
    -
    - ${_('Commit Message')}: -
    -
    -
    - -
    +
    +
    -
    - ${h.reset('reset',_('Cancel'),class_="btn btn-small")} - ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-success")} +
    + ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
    ${h.end_form()}
    + diff --git a/rhodecode/templates/files/files_browser.mako b/rhodecode/templates/files/files_browser.mako --- a/rhodecode/templates/files/files_browser.mako +++ b/rhodecode/templates/files/files_browser.mako @@ -2,53 +2,60 @@
    - ${h.form(h.current_route_path(request), method='GET', id='at_rev_form')} +
    - ${h.hidden('refs_filter')} + -
    ${h.text('at_rev',value=c.commit.idx)}
    + + ${h.hidden('refs_filter')} +
    - ${h.end_form()} - - % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): - - % endif - % if c.enable_downloads: - <% at_path = '{}.zip'.format(request.GET.get('at') or c.commit.raw_id[:6]) %> -
    - - ${_('Download tree at {}').format(at_path)} + % endif + + % if c.enable_downloads: + <% at_path = '{}'.format(request.GET.get('at') or c.commit.raw_id[:6]) %> +
    + % if c.f_path == '/': + + ${_('Download full tree ZIP')} + + % else: + + ${_('Download this tree ZIP')} + + % endif +
    + % endif + +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    -
    + ## file tree is computed from caches, and filled in
    ${c.file_tree |n} diff --git a/rhodecode/templates/files/files_browser_tree.mako b/rhodecode/templates/files/files_browser_tree.mako --- a/rhodecode/templates/files/files_browser_tree.mako +++ b/rhodecode/templates/files/files_browser_tree.mako @@ -1,5 +1,11 @@ -
    - +<% + if request.GET.get('at'): + query={'at': request.GET.get('at')} + else: + query=None +%> +
    +
    @@ -11,19 +17,13 @@ - %if c.file.parent: - - + - - - - - - %endif + %for cnt,node in enumerate(c.file): diff --git a/rhodecode/templates/files/files_delete.mako b/rhodecode/templates/files/files_delete.mako --- a/rhodecode/templates/files/files_delete.mako +++ b/rhodecode/templates/files/files_delete.mako @@ -1,7 +1,7 @@ <%inherit file="/base/base.mako"/> <%def name="title()"> - ${_('%s Files Delete') % c.repo_name} + ${_('{} Files Delete').format(c.repo_name)} %if c.rhodecode_name: · ${h.branding(c.rhodecode_name)} %endif @@ -11,32 +11,40 @@ ${self.menu_items(active='repositories')} -<%def name="breadcrumbs_links()"> - ${_('Delete file')} @ ${h.show_id(c.commit)} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_subnav()"> ${self.repo_menu(active='files')} <%def name="main()"> +
    -
    - ${self.repo_page_title(c.rhodecode_db_repo)} + +
    + ${_('Delete file')} @ ${h.show_id(c.commit)} + % if c.commit.branch: + + ${c.commit.branch} + + % endif
    -
    - ${self.breadcrumbs()} -
    - ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', class_="form-horizontal", request=request)} + + ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
    -
    -
    - ${_('Path')}: -
    -
    - ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} -
    +
    + +
  • + + +
  • +
    @@ -56,20 +64,26 @@
    -
    - ${_('Commit Message')}: -
    -
    -
    - -
    +
    +
    -
    - ${h.reset('reset',_('Cancel'),class_="btn btn-small btn-danger")} - ${h.submit('commit',_('Delete File'),class_="btn btn-small btn-danger-action")} +
    + ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-danger-action")}
    ${h.end_form()}
    + + + + diff --git a/rhodecode/templates/files/files_edit.mako b/rhodecode/templates/files/files_edit.mako --- a/rhodecode/templates/files/files_edit.mako +++ b/rhodecode/templates/files/files_edit.mako @@ -1,7 +1,7 @@ <%inherit file="/base/base.mako"/> <%def name="title()"> - ${_('%s File Edit') % c.repo_name} + ${_('{} Files Edit').format(c.repo_name)} %if c.rhodecode_name: · ${h.branding(c.rhodecode_name)} %endif @@ -11,187 +11,114 @@ ${self.menu_items(active='repositories')} -<%def name="breadcrumbs_links()"> - ${_('Edit file')} @ ${h.show_id(c.commit)} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_subnav()"> ${self.repo_menu(active='files')} <%def name="main()"> -<% renderer = h.renderer_from_filename(c.f_path)%> +
    -
    - ${self.repo_page_title(c.rhodecode_db_repo)} + +
    + ${_('Edit file')} @ ${h.show_id(c.commit)} + % if c.commit.branch: + + ${c.commit.branch} + + % endif
    -
    - ${self.breadcrumbs()} -
    + + ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
    -
    -
    - ${_('Path')}: -
    -
    -
    - ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.f_path)} +
    +
    + +
  • + + +
  • +
    +
    - ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)} -
    -
    -
    - - ${h.link_to("r%s:%s" % (c.file.commit.idx,h.short_id(c.file.commit.raw_id)),h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.file.commit.raw_id))} - ${h.format_byte_size_binary(c.file.size)} - ${c.file.mimetype} -
    - - ${_('history')} - +
    - % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): - % if not c.file.is_binary: - %if True: - ${h.link_to(_('source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")} - %else: - ${h.link_to(_('annotation'),h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),class_="btn btn-mini")} - %endif +
    +
    +
    + ${_('Edit')} +
    + +
    + ${_('Preview')} +
    - - ${_('raw')} - - - ${_('download')} - - % endif - % endif +
    + ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off')),])} +
    +
    + ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))],enable_filter=True)} +
    -
    -
    - - ${'%s /' % c.file.dir_path if c.file.dir_path else c.file.dir_path} - - ${h.dropdownmenu('set_mode','plain',[('plain',_('plain'))],enable_filter=True)} - - ${h.dropdownmenu('line_wrap', 'off', [('on', _('on')), ('off', _('off')),])} - - -
    -
    -
    -
    
    -                
    -                
    +
    +
    
    +                    
    +                    
    +
    -
    - ${_('Commit Message')}: -
    -
    -
    - -
    +
    +
    -
    - ${h.reset('reset',_('Cancel'),class_="btn btn-small")} - ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-success")} +
    + ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
    ${h.end_form()}
    diff --git a/rhodecode/templates/files/files_pjax.mako b/rhodecode/templates/files/files_pjax.mako --- a/rhodecode/templates/files/files_pjax.mako +++ b/rhodecode/templates/files/files_pjax.mako @@ -1,7 +1,7 @@ <%def name="title(*args)"> - ${_('%s Files') % c.repo_name} + ${_('{} Files').format(c.repo_name)} %if hasattr(c,'file'): - · ${h.safe_unicode(c.file.path) or '\\'} + · ${(h.safe_unicode(c.file.path) or '\\')} %endif %if c.rhodecode_name: @@ -9,47 +9,26 @@ %endif -
    +
    +
    - -
    - ${_('Show More')} -
    +
    % if c.file.is_submodule(): Submodule ${h.escape(c.file.name)} % elif c.file.is_dir(): - <%include file='file_tree_detail.mako'/> + <%include file='files_tree_header.mako'/> % else: - <%include file='files_detail.mako'/> + <%include file='files_source_header.mako'/> % endif
    - % if c.file.is_dir(): - - <%include file='files_browser.mako'/> % else: - - <%include file='files_source.mako'/> % endif -
    \ No newline at end of file +
    diff --git a/rhodecode/templates/files/files_source.mako b/rhodecode/templates/files/files_source.mako --- a/rhodecode/templates/files/files_source.mako +++ b/rhodecode/templates/files/files_source.mako @@ -1,81 +1,110 @@ <%namespace name="sourceblock" file="/codeblocks/source.mako"/> -
    -
    -
    - - - - ${c.file.unicode_path_safe} - - - -
    +
    +
    +
    +
    + ## loads the history for a file + ${h.hidden('file_refs_filter')} +
    + +
    + + ## Download + % if c.lf_node: + + ${_('Download largefile')} + + % else: + + ${_('Download file')} + + % endif + %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): + ## on branch head, can edit files + %if c.on_branch_head and c.branch_or_raw_id: + ## binary files are delete only + % if c.file.is_binary: + ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing binary files not allowed'))} + ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path),class_="btn btn-danger")} + % else: + + ${_('Edit on branch: ')}${c.branch_name} + + + + ${_('Delete')} + + % endif + ## not on head, forbid all + % else: + ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing files allowed only when on branch head commit'))} + ${h.link_to(_('Delete'), '#Delete', class_="btn btn-default btn-danger disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))} + % endif + %endif + +
    +
    +
    + +
    +
    + +
    +
    +
    + ${c.file} +
    + +
    + +
    + ${c.file.lines()[0]} ${_ungettext('line', 'lines', c.file.lines()[0])} + + | ${h.format_byte_size_binary(c.file.size)} % if c.lf_node: | ${_('LargeFile')} ${h.format_byte_size_binary(c.lf_node.size)} % endif - - ${c.file.lines()[0]} ${_ungettext('line', 'lines', c.file.lines()[0])} - | ${h.format_byte_size_binary(c.file.size)} | ${c.file.mimetype} | ${h.get_lexer_for_filenode(c.file).__class__.__name__} - +
    +
    -
    - - ${_('History')} - - | - %if c.annotate: - ${h.link_to(_('Source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} - %else: - ${h.link_to(_('Annotation'), h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} - %endif - | ${h.link_to(_('Raw'), h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} - | - % if c.lf_node: - - ${_('Download largefile')} - - % else: - - ${_('Download')} - - % endif + +
    +
    + ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'))} +
    - %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): - | - %if c.on_branch_head and c.branch_or_raw_id and not c.file.is_binary: - - ${_('Edit on Branch:{}').format(c.branch_name)} - - | ${_('Delete')} - - %elif c.on_branch_head and c.branch_or_raw_id and c.file.is_binary: - ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing binary files not allowed'))} - | ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit'),class_="btn-danger btn-link")} - %else: - ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing files allowed only when on branch head commit'))} - | ${h.link_to(_('Delete'), '#', class_="btn btn-danger btn-link disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))} - %endif - %endif +
    + + ${_('History')} + + | + %if c.annotate: + ${h.link_to(_('Source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} + %else: + ${h.link_to(_('Annotation'), h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} + %endif + | ${h.link_to(_('Raw'), h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))} + +
    +
    -
    -
    -
    - %if c.file.is_binary: - <% rendered_binary = h.render_binary(c.repo_name, c.file)%> - % if rendered_binary: - ${rendered_binary} - % else: -
    - ${_('Binary file (%s)') % c.file.mimetype} -
    - % endif - %else: + +
    + + %if c.file.is_binary: + <% rendered_binary = h.render_binary(c.repo_name, c.file)%> + % if rendered_binary: + ${rendered_binary} + % else: +
    + ${_('Binary file (%s)') % c.file.mimetype} +
    + % endif + %else: % if c.file.size < c.visual.cut_off_limit_file: %if c.renderer and not c.annotate: ## pick relative url based on renderer @@ -106,7 +135,8 @@ %endif %endif
    -
    + +
    \ No newline at end of file + diff --git a/rhodecode/templates/files/file_tree_detail.mako b/rhodecode/templates/files/files_tree_header.mako rename from rhodecode/templates/files/file_tree_detail.mako rename to rhodecode/templates/files/files_tree_header.mako --- a/rhodecode/templates/files/file_tree_detail.mako +++ b/rhodecode/templates/files/files_tree_header.mako @@ -1,37 +1,46 @@ +<%namespace name="base" file="/base/base.mako"/> <%namespace name="file_base" file="/files/base.mako"/> -
    -
    - ${_('Description')}: -
    -
    ${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}
    -
    +
    +
    +
    + +
    + ${base.gravatar(c.commit.author_email, 30)} +
    -
    -
    - ${_('Description')}: -
    -
    ${h.urlify_commit_message(c.commit.message,c.repo_name)}
    -
    +
    +
    +
    ${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}
    +
    + +
    +
    ${h.urlify_commit_message(c.commit.message,c.repo_name)}
    +
    - +
    + ${h.link_to_user(c.commit.author)} - ${h.age_component(c.commit.date)} +
    +
    +
    -
    -
    - ${_('References')}: -
    -
    -
    - - ${h.show_id(c.commit)} - +
    +
    + + ${h.show_id(c.commit)} + - ${file_base.refs(c.commit)} + ${file_base.refs(c.commit)} +
    +
    + +
    + +
    + ${_('Show More')}
    - - diff --git a/rhodecode/templates/files/files_upload.mako b/rhodecode/templates/files/files_upload.mako new file mode 100644 --- /dev/null +++ b/rhodecode/templates/files/files_upload.mako @@ -0,0 +1,211 @@ +<%inherit file="/base/base.mako"/> + +<%def name="title()"> + ${_('{} Files Upload').format(c.repo_name)} + %if c.rhodecode_name: + · ${h.branding(c.rhodecode_name)} + %endif + + +<%def name="menu_bar_nav()"> + ${self.menu_items(active='repositories')} + + +<%def name="breadcrumbs_links()"> + +<%def name="menu_bar_subnav()"> + ${self.repo_menu(active='files')} + + +<%def name="main()"> + +
    + ## Template for uploads + + +
    + ${_('Upload new file')} @ ${h.show_id(c.commit)} + % if c.commit.branch: + + ${c.commit.branch} + + % endif +
    + + <% form_url = h.route_path('repo_files_upload_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path) %> + ##${h.secure_form(form_url, id='eform', enctype="multipart/form-data", request=request)} +
    +
    +
      + +
    • + +
    • +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    + ${_("Drag'n Drop files here or")} ${_('Choose your files')}.
    +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    + ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")} +
    +
    + ##${h.end_form()} + + + +
    + + + diff --git a/rhodecode/templates/forks/fork.mako b/rhodecode/templates/forks/fork.mako --- a/rhodecode/templates/forks/fork.mako +++ b/rhodecode/templates/forks/fork.mako @@ -20,10 +20,6 @@ <%def name="main()">
    -
    - ${self.repo_page_title(c.rhodecode_db_repo)} -
    - ${h.secure_form(h.route_path('repo_fork_create',repo_name=c.rhodecode_db_repo.repo_name), request=request)}
    diff --git a/rhodecode/templates/forks/forks.mako b/rhodecode/templates/forks/forks.mako --- a/rhodecode/templates/forks/forks.mako +++ b/rhodecode/templates/forks/forks.mako @@ -8,9 +8,7 @@ %endif -<%def name="breadcrumbs_links()"> - ${_('Forks')} - +<%def name="breadcrumbs_links()"> <%def name="menu_bar_nav()"> ${self.menu_items(active='repositories')} @@ -23,7 +21,7 @@ <%def name="main()">
    - ${self.repo_page_title(c.rhodecode_db_repo)} +
    ${_('Name')}
    - - .. - +
    + + ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'), limit_items=True)} +
    @@ -38,8 +38,9 @@ % endif % else: - - ${node.name} + + + ${node.name} % endif
    -
    -
    +
    -
    +